//############################################################################
//
// LaserBoy !!!
//
// by James Lehman
// Extra Stimulus Inc.
// james@akrobiz.com
//
// began: October 2003
//
// Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 James Lehman.
// This source is distributed under the terms of the GNU General Public License.
//
// LaserBoy_space.hpp is part of LaserBoy.
//
// LaserBoy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// LaserBoy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with LaserBoy. If not, see <http://www.gnu.org/licenses/>.
//
//############################################################################
#ifndef __LASERBOY_SPACE_DEFINITIONS__
#define __LASERBOY_SPACE_DEFINITIONS__

//############################################################################
#include "LaserBoy_frame_set.hpp"
#include "LaserBoy_palette_set.hpp"

//############################################################################
class LaserBoy_GUI_base;

//############################################################################
class LaserBoy_space : public LaserBoy_frame_set, public LaserBoy_palette_set
{
public:
    LaserBoy_space(LaserBoy_GUI_base* gui);
    //------------------------------------------------------------------------
virtual
   ~LaserBoy_space()
    {
        bmp_free (&bmp);
        bmp_free (&background);
    }
    //------------------------------------------------------------------------
    LaserBoy_frame& operator [] (int index) // does not set frame_index
                    {
                        if(number_of_frames())
                        {
                            if(index >= number_of_frames())
                                index = 0;
                            if(index < 0)
                                index = number_of_frames() - 1;
                            return LaserBoy_frame_set::at(index);
                        }
                        return null_frame;
                    }
    //------------------------------------------------------------------------
    LaserBoy_space& operator += (const LaserBoy_frame_set& frames)
                    {
                        LaserBoy_frame_set::insert(LaserBoy_frame_set::end(),
                                                   frames.begin(), frames.end()
                                                  );
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_space& operator  = (const LaserBoy_space& space)
                    {
                        LaserBoy_palette_set::clear();
                        LaserBoy_palette_set::reserve(space.number_of_palettes());

                        LaserBoy_palette_set::insert (LaserBoy_palette_set::end(),
                                                      space.LaserBoy_palette_set::begin(),
                                                      space.LaserBoy_palette_set::end()
                                                     );
                        //....................................................
                        LaserBoy_frame_set::clear();
                        LaserBoy_frame_set::reserve(space.number_of_frames());
                        LaserBoy_frame_set::insert (LaserBoy_frame_set::end(),
                                                    space.LaserBoy_frame_set::begin(),
                                                    space.LaserBoy_frame_set::end()
                                                   );
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_space& operator  = (const LaserBoy_frame_set& frames)
                    {
                        LaserBoy_frame_set::clear();
                        LaserBoy_frame_set::reserve(frames.number_of_frames());
                        LaserBoy_frame_set::insert (LaserBoy_frame_set::end(),
                                                    frames.LaserBoy_frame_set::begin(),
                                                    frames.LaserBoy_frame_set::end()
                                                   );
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_space& operator += (const LaserBoy_frame& frame)
                    {
                        LaserBoy_frame_set::push_back(frame);
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_space& operator += (const LaserBoy_palette_set& palettes)
                    {
                        LaserBoy_palette_set::insert(LaserBoy_palette_set::end(),
                                                     palettes.begin(),
                                                     palettes.end()
                                                    );
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_space& operator += (const LaserBoy_palette& palette)
                    {
                        LaserBoy_palette_set::push_back(palette);
                        return *this;
                    }
    //------------------------------------------------------------------------
    void clear_frames()
                {
                    LaserBoy_frame_set::clear();
                    return;
                }
    //------------------------------------------------------------------------
    void clear_palettes()
                {
                    LaserBoy_palette_set::clear();
                    return;
                }
    //------------------------------------------------------------------------
    bool have_offsets()
                {
                    if(wave_offsets[0]) return true;
                    if(wave_offsets[1]) return true;
                    if(wave_offsets[2]) return true;
                    if(wave_offsets[3]) return true;
                    if(wave_offsets[4]) return true;
                    if(wave_offsets[5]) return true;
                    if(wave_offsets[6]) return true;
                    if(wave_offsets[7]) return true;
                    return false;
                }
    //------------------------------------------------------------------------
    void clean_screen                 ();
    //------------------------------------------------------------------------
    void rename_all_frames            (string name);
    //------------------------------------------------------------------------
    bool omit_palette                 (int index);
    void clear_unused_palettes        ();
    void sync_rgb_and_palette         ();
    void minimize_tables_and_palettes ();
    void best_reduce_all_to_palette   ();
    //------------------------------------------------------------------------
    bool load_wtf_file                (string wtf_file);
    bool save_wtf_file                (string wtf_file);
    //------------------------------------------------------------------------
    void load_color_rescale_files     ();
    int  load_color_rescale_file      (int color_channel);
    int  color_rescales_flags         ();
    //------------------------------------------------------------------------
    void load_frame_effects           ();
    void load_frame_set_effects       ();
    int  call_frame_effect            (string name);
    int  call_frame_set_effect        (string name);
    //------------------------------------------------------------------------
    void load_background_bitmap       (struct LaserBoy_bmp* bmp);
    bool load_background_bitmap       (string file             );
    void clear_background_bitmap      ();
    void recolor_background           ();
    //------------------------------------------------------------------------
    void simplify_view_angle()
             {
                 while(view_angle.x < 0)
                     view_angle.x += two_pi;
                 while(view_angle.x > two_pi)
                     view_angle.x -= two_pi;
                 while(view_angle.y < 0)
                     view_angle.y += two_pi;
                 while(view_angle.y > two_pi)
                     view_angle.y -= two_pi;
                 while(view_angle.z < 0)
                     view_angle.z += two_pi;
                 while(view_angle.z > two_pi)
                     view_angle.z -= two_pi;
             }
    //------------------------------------------------------------------------
    LaserBoy_bmp* p_bmp           () { return &bmp;            }
    LaserBoy_bmp* p_background    () { return &background;     }
    LaserBoy_bmp* p_background_bmp() { return &background_bmp; }
    //------------------------------------------------------------------------
    void undo_wave_temp(fstream &in, fstream &out, string file_name)
    {
        if(in.is_open())
            in.close();
        if(out.is_open())
            out.close();
        remove(file_name.c_str());
        rename(  (file_name + ".tmp").c_str()
               , file_name.c_str()
              );
        return;
    }
    //------------------------------------------------------------------------
    bool apply_wave_offsets_prep       (string file);
    bool overwirte_wave_offsets        (string file);
    bool invert_wave_prep              (string file);
    bool invert_signals_prep           (string file);
    bool clear_wave_polarity_list      (string file, bool global_flip_flop);
    bool apply_color_rescales_prep     (string file);
    bool omit_color_rescales           (string file);
    bool save_color_rescales           (string file,    string out_name   );
    bool black_level_to_wave_prep      (string file_in, string file_out   );
    bool bit_resolution_to_wave_prep   (string file_in, string file_out   );
    //------------------------------------------------------------------------
    bool split_wave_XY_r_g_b_i_LR_prep (string file,
                                        string dir_wav,
                                        string dir_unformatted,
                                        string dir_audio
                                       );
    //------------------------------------------------------------------------
    bool split_wave_XY_rg_bi_LR_prep   (string file,
                                        string dir_wav,
                                        string dir_unformatted,
                                        string dir_audio
                                       );
    //------------------------------------------------------------------------
    bool join_XY_r_g_b_i_waves_prep    (string file_XY,
                                        string file_r,
                                        string file_g,
                                        string file_b,
                                        string file_i,
                                        string file_out,
                                        bool   global_polarity
                                       );
    //------------------------------------------------------------------------
    bool join_XY_rg_b_waves_prep       (string file_XY,
                                        string file_rg,
                                        string file_b,
                                        string file_out,
                                        bool   global_polarity
                                       );
    //------------------------------------------------------------------------
    bool join_XY_rg_b_LR_waves_prep    (string file_XY,
                                        string file_rg,
                                        string file_b,
                                        string file_LR,
                                        string file_out,
                                        bool   global_polarity
                                       );
    //------------------------------------------------------------------------
    bool add_audio_to_wave_prep        (string file_laser,
                                        string file_audio,
                                        string file_out
                                       );
    //------------------------------------------------------------------------
    void apply_wave_offsets        (fstream&             wave_in,
                                    fstream&             wave_out,
                                    LaserBoy_wave_header wave_in_header
                                   );
    //------------------------------------------------------------------------
    void invert_wave               (fstream&             wave_in,
                                    fstream&             wave_out,
                                    LaserBoy_wave_header wave_in_header
                                   );
    //------------------------------------------------------------------------
    void invert_signals            (fstream&             wave_in,
                                    fstream&             wave_out,
                                    LaserBoy_wave_header wave_in_header
                                   );
    //------------------------------------------------------------------------
    void black_level_to_wave       (fstream&             wave_in,
                                    fstream&             wave_out,
                                    LaserBoy_wave_header wave_in_header
                                   );
    //------------------------------------------------------------------------
    void bit_resolution_to_wave    (fstream&             wave_in,
                                    fstream&             wave_out,
                                    LaserBoy_wave_header wave_in_header
                                   );
    //------------------------------------------------------------------------
    void apply_color_rescales      (fstream&             wave_in,
                                    fstream&             wave_out,
                                    LaserBoy_wave_header wave_in_header
                                   );
    //------------------------------------------------------------------------
    void split_wave_XY_r_g_b_i_LR  (LaserBoy_wave_header wave_in_header,
                                    fstream&             wave_in,
                                    fstream&             wave_out_XY,
                                    fstream&             wave_out_r,
                                    fstream&             wave_out_g,
                                    fstream&             wave_out_b,
                                    fstream&             wave_out_i,
                                    fstream&             wave_out_LR
                                   );
    //------------------------------------------------------------------------
    void split_wave_XY_rg_bi_LR    (LaserBoy_wave_header wave_in_header,
                                    fstream&             wave_in,
                                    fstream&             wave_out_XY,
                                    fstream&             wave_out_rg,
                                    fstream&             wave_out_bi,
                                    fstream&             wave_out_LR
                                   );
    //------------------------------------------------------------------------
    void join_XY_r_g_b_i_waves     (fstream& in_XY,
                                    fstream& in_r,
                                    fstream& in_g,
                                    fstream& in_b,
                                    fstream& in_i,
                                    fstream& out,
                                    bool     global_polartity
                                   );
    //------------------------------------------------------------------------
    void join_XY_rg_b_waves        (fstream& in_XY,
                                    fstream& in_rg,
                                    fstream& in_b,
                                    fstream& out,
                                    bool     global_polartity
                                   );
    //------------------------------------------------------------------------
    void join_XY_rg_b_LR_waves     (fstream& in_XY,
                                    fstream& in_rg,
                                    fstream& in_b,
                                    fstream& in_LR,
                                    fstream& out,
                                    bool     global_polartity
                                   );
    //------------------------------------------------------------------------
    void join_XY_rg_b_00_waves     (fstream& in_XY,
                                    fstream& in_rg,
                                    fstream& in_b,
                                    fstream& out,
                                    bool     global_polartity
                                   );
    //------------------------------------------------------------------------
    void add_audio_to_wave         (LaserBoy_wave_header wave_in_header_laser,
                                    LaserBoy_wave_header wave_in_header_audio,
                                    fstream&             in_laser,
                                    fstream&             in_audio,
                                    fstream&             out
                                   );
    //------------------------------------------------------------------------
    void add_silence_to_wave       (LaserBoy_wave_header wave_in_header_laser,
                                    fstream&             in_laser,
                                    fstream&             out
                                   );
    //------------------------------------------------------------------------
    void format_wave               (LaserBoy_wave_header wave_in_header_laser,
                                    fstream&             in_laser,
                                    fstream&             out,
                                    bool                 global_polartity,
                                    bool                 write_eof_bits,
                                    int                  channel_5
                                   );
    //------------------------------------------------------------------------
    string LaserBoy_wave_signal_id_to_name  (const short& signal_id) const;
    string LaserBoy_wave_LSB_tag_to_name    (const short& LSB_tag  ) const;
    string LaserBoy_dots_setting_id_to_name (const int&   id       ) const;
    //------------------------------------------------------------------------
    void   tell(LaserBoy_wave_header header, string label) const;
    //------------------------------------------------------------------------
    bool    show_vertices          ,
            show_blanking          ,
            show_intro             ,
            show_bridge            ,
            show_coda              ,
            show_cursors           ,
            show_color_cursor      ,
            show_fixed_bounds      ,
            show_fixed_origin      ,
            show_floating_axis     ,
            show_floating_bounds   ,
            show_fulcrum           ,
            show_indices           ,
            show_effects_generation,
            show_background_bitmap ,
            show_onion_skin        ,
            show_onion_visuals     ,
            show_menu              ,
            show_palette           ,
            show_target_palette    ,
            show_stats             ,
            show_TUI_clue          ,
            show_frame_stats       ,
            show_frame_set_stats   ,
            show_Z_as_order        ,
            show_quad_view         ,
            ui_visuals_flip_flop   ,
            loop_animation         ,
            approximate_frame_rate ,
            wave_show_vertices     ,
            wave_show_blanks       ,
            wave_real_time         ,
            wave_show_inverted     ,
            wave_clean_screen      ,
            wave_loop              ,
            auto_scale_real        ,
            maintain_real_origin   ,
            save_true_color_dxf    ,
            black_dwell_vertices   ,
            auto_flatten_z         ,
            z_from_unformatted     ,
            no_equivalent_vectors  ,
            invert_wave_output     ,
            auto_minimize          ,
            auto_apply_offsets     ,
            auto_apply_rescales    ,
            no_black_match         ,
            allow_lit_black        ,
            dumb_file_format       ,
            save_txt_with_color    ,
            save_txt_unit          ,
            save_txt_color_hex     ,
            save_txt_named_palettes,
            save_fmtd_wav_splits   ;

    short   color_rescale_r   [256],
            color_rescale_g   [256],
            color_rescale_b   [256],
            color_rescale_i   [256];

    short  *color_rescale       [4];

    int     black_level            ,
            number_of_skins        ,
            sample_rate            ,
            lit_dwell_overhang     ,
            dots_setting           ,
            dwell_on_dot           ,
            output_bmp_size        ,
            font_size_factor       ,
            background_bmp_scale   ,
            signal_if_not_z        ,
            unframed_wave_stride   ,
            displacement_step      ,
            channels_of_wav_out    ,
            signal_bit_mask     [8], // number of bits to mask from the LSB end
            signal_polarity     [8], // -1 unknown, 0 positive, 1 negative
            wave_offsets        [8]; // in samples

    double  lit_delta_max          ,
            blank_delta_max        ,
            max_dwell_microsec     ,
            max_wag_microsec       ,
            insignificant_distance ,
            insignificant_angle    ,
            recolor_span_factor    ,
            onion_skin_fade        ,
            rendered_arc_angle     , // in degrees
            frames_per_second      ,
            still_frame_duration   ,
            rotation_step          , // in radians!
            magnitude_step         ,
            magnitude_step_up      ,
            magnitude_step_dn      ;

    struct
    LaserBoy_bmp       bmp           , // a memory clone of screen
                       background    , // empty for clearing screen
                       background_bmp; // possibly a bitmap picture

    string             bg_file_name,
                       color_rescale_file[4]; // txt file names for each color channel

    LaserBoy_color     bg_color;

    LaserBoy_3D_double fulcrum    ,
                       view_angle ,
                       view_scale ,
                       view_offset;

    vector<string>     frame_effect_names    ,
                       frame_set_effect_names;

    vector<LaserBoy_frame_effect>     frame_effects    ;
    vector<LaserBoy_frame_set_effect> frame_set_effects;

    LaserBoy_GUI_base*  p_GUI;
    //------------------------------------------------------------------------
};

//############################################################################
#endif

//############################################################################
//////////////////////////////////////////////////////////////////////////////
//############################################################################
