/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "editor/editor.hh"
#include "saver_id.hh"
#include "editor/e_state.hh"
#include "editor/e_res.hh"
#include "lisp/li_init.hh"
#include "lisp/lisp.hh"
#include "saver.hh"

void g1_editor_class::show_undo_state()
{
  int t=undo.tail, t_undos=0, t_redos=0, rt=undo.redo_tail;
  while (t!=undo.head)
  {
    t_undos++;
    t=(t+1)%undo.max;
  }

  while (rt!=undo.head)
  {
    t_redos++;
    rt=(rt+1)%undo.max;
  }   
}


void g1_editor_class::save_undo_info(w32 sections, i4_const_str &fname)
{
  li_call("redraw");

  changed();  // note that map is about to be changed so the user can save if they want

  i4_file_class *fp=i4_open(fname, I4_WRITE);
  if (!fp)
  {
    i4_mkdir(g1_ges("undo_dir"));
    fp=i4_open(fname, I4_WRITE);
  }
    
  if (fp)
  {
    g1_saver_class *sfp=new g1_saver_class(fp, i4_T);

    sfp->mark_section(G1_SECTION_MAP_SECTIONS_V1);
    sfp->write_32(sections);            
    get_map()->save(sfp, sections);
    sfp->begin_data_write();

    sfp->mark_section(G1_SECTION_MAP_SECTIONS_V1);
    sfp->write_32(sections);
    get_map()->save(sfp, sections);      
    delete sfp;
  }
}


void g1_editor_class::add_undo(w32 sections)
{
  if (g1_map_is_loaded() && undo.allow)
  {
    sections&=(~G1_MAP_VIEW_POSITIONS);   // don't save changes to the camera positions

    if (sections & G1_MAP_OBJECTS)      // if saving objects, save player info because it has 
      sections |= G1_MAP_PLAYERS;       // object references
    
    
    if (sections & (G1_MAP_CELLS 
                    | G1_MAP_VERTS 
                    | G1_MAP_OBJECTS 
                    | G1_MAP_LIGHTS 
                    | G1_MAP_SELECTED_VERTS))
      get_map()->recalc |= G1_RECALC_RADAR_VIEW;

    if (sections & (G1_MAP_CELLS | G1_MAP_VERTS | G1_MAP_SELECTED_VERTS))
      get_map()->recalc |= G1_RECALC_WATER_VERTS;


    if (!sections) return;

    g1_edit_state.hide_focus();

    if (((undo.head+1) % undo.max) == undo.tail)
      undo.tail = (undo.tail+1)%undo.max;

    int cur_undo=undo.head;

    i4_str *undo_file=g1_ges("undo_file").sprintf(100,cur_undo);

    save_undo_info(sections, *undo_file);


    delete undo_file;

    can_undo=i4_T;
    can_redo=i4_F;

    undo.head=(undo.head+1) % undo.max;
    undo.redo_tail=undo.head;

    g1_edit_state.show_focus();
  }

  show_undo_state();
}


li_object *g1_add_undo(li_object *o, li_environment *env)
{
  g1_editor_instance.add_undo(li_get_int(li_eval(li_car(o,env),env),env));
  return 0;
}

li_automatic_add_function(g1_add_undo, "add_undo");


void g1_editor_class::do_undo()
{


  if (g1_map_is_loaded() && undo.redo_tail!=undo.tail)
  {
    i4_str *old_name=new i4_str(g1_get_map()->get_filename());

    g1_edit_state.hide_focus();

    undo.redo_tail=(undo.redo_tail + undo.max - 1) % undo.max;

    i4_str *undo_file=g1_ges("undo_file").sprintf(100,undo.redo_tail);
    i4_file_class *fp=i4_open(*undo_file);
    if (fp)
    {
      g1_loader_class *lfp=g1_open_save_file(fp, i4_T);
      if (lfp->goto_section(G1_SECTION_MAP_SECTIONS_V1))
      {
        w32 sections=lfp->read_32();
     
        i4_str *redo_file=g1_ges("redo_file").sprintf(100,undo.redo_tail);        
        save_undo_info(sections, *redo_file);

        delete redo_file;

        undo.allow=0;

        if ((sections|G1_MAP_VIEW_POSITIONS)==G1_MAP_ALL)
          g1_load_level(*undo_file, 1, 0);   // need to reload textures for this one
        else
          get_map()->load(lfp, sections);

        undo.allow=1;
      }

      delete lfp;
    }
    delete undo_file;

    g1_get_map()->set_filename(*old_name);
    delete old_name;

    if (undo.redo_tail==undo.tail)
      can_undo=i4_F;

    can_redo=i4_T;
    li_call("redraw");

    g1_edit_state.show_focus();
  }

  show_undo_state();
}

void g1_editor_class::do_redo()
{
  if (g1_map_is_loaded() && undo.redo_tail!=undo.head)
  {
    i4_str *old_name=new i4_str(g1_get_map()->get_filename());

    g1_edit_state.hide_focus();

    i4_str *redo_file=g1_ges("redo_file").sprintf(100,undo.redo_tail);
    i4_file_class *fp=i4_open(*redo_file);
    if (fp)
    {    
      g1_loader_class *lfp=g1_open_save_file(fp, i4_T);
      if (lfp)
      {
        if (lfp->goto_section(G1_SECTION_MAP_SECTIONS_V1))
        {
          w32 sections=lfp->read_32();
          undo.allow=0;

          if (sections==G1_MAP_ALL)
            g1_load_level(*redo_file, 1, 0);   // need to reload textures for this one
          else
            get_map()->load(lfp, sections);

          undo.allow=1;
        }
        delete lfp;
      }
    }
    delete redo_file;

    g1_get_map()->set_filename(*old_name);
    delete old_name;


    undo.redo_tail = (undo.redo_tail + 1) % undo.max;
    
    if (undo.redo_tail==undo.head)
    {
      can_redo=i4_F;
    }

    li_call("redraw");

    g1_edit_state.show_focus();
  }

  show_undo_state();
}