/**********************************************************************
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/dialogs/scene.hh"
#include "gui/text_input.hh"
#include "gui/text.hh"
#include "gui/button.hh"
#include "m_flow.hh"
#include "g1_speed.hh"
#include "editor/editor.hh"
#include "window/colorwin.hh"
#include "editor/edit_id.hh"
#include "window/win_evt.hh"
#include "gui/smp_dial.hh"
#include "gui/image_win.hh"
#include "editor/e_res.hh"

class g1_scene_change_order_event : public i4_object_message_event_class
{
public:
  sw32 o,n;
  g1_scene_change_order_event(void *object, 
                              w32 sub_type, 
                              w32 old_order,
                              w32 new_order)
    : i4_object_message_event_class(object, sub_type),
      o(old_order),
      n(new_order)            {}

  virtual dispatch_time when()  { return LATER; }
  virtual i4_event  *copy() { return new g1_scene_change_order_event(object, sub_type, o,n); }
};



class g1_delete_scene_event_class : public i4_object_message_event_class
{
public:
  sw32 sn;
  g1_delete_scene_event_class(void *object,
                              w32 sub_type,
                              sw32 scene_number)
    : i4_object_message_event_class(object, sub_type),
      sn(scene_number)
  {}
  virtual dispatch_time when()  { return LATER; }
  virtual i4_event  *copy() { return new g1_delete_scene_event_class(object, sub_type, sn); }
};

class g1_cut_scene_editor_class : public i4_parent_window_class
{
  sw32 scene_number, start_time;

  g1_cut_scene_class *cs;
  i4_graphical_style_class *style;
  i4_text_input_class *scene_number_input;
  i4_text_input_class *scene_name_input;
  i4_text_input_class *scene_wav_input;
  i4_event_handler_class *eh;

  i4_window_class *dialog_active;

public:
  enum { DELETE_ME,
         DELETE_YES,
         DELETE_NO };
  
  char *name() { return "cut_scene_editor"; }

  ~g1_cut_scene_editor_class()
  {
    if (dialog_active)
      delete dialog_active;
  }

  sw32 tbox_width() { return 50; }
  sw32 name_width() { return 200; }
  sw32 wav_width() { return 150; }

  void send_delete_me()
  {
    g1_delete_scene_event_class del(eh, g1_scene_editor_class::DELETE_SCENE, scene_number);
    i4_kernel.send_event(eh, &del);
  }

  void create_delete_confirm_window()
  {
    dialog_active=i4_create_yes_no_dialog(root_window(),
                            style,
                            g1_ges("delete_title"),
                            g1_ges("delete_message"),
                            g1_ges("yes"), g1_ges("no"),
                            this,
                            new i4_object_message_event_class(this, DELETE_YES),
                            new i4_object_message_event_class(this, DELETE_NO));    
  }

  void receive_event(i4_event *ev)
  {
    if (ev->type()==i4_event::OBJECT_MESSAGE)
    {
      CAST_PTR(oev, i4_object_message_event_class, ev);
    
      if (oev->object==this)
      {
        switch (oev->sub_type)
        {
          case DELETE_ME :
            create_delete_confirm_window(); break;
          case DELETE_NO :
            dialog_active=0;
            break;

          case DELETE_YES :
            dialog_active=0;
            send_delete_me();
            break;                        
        }
      }
      else if (oev->object==scene_number_input)
      {
        CAST_PTR(tev, i4_text_change_notify_event, ev);
        i4_const_str::iterator i=tev->new_text->begin();
        sw32 sn=i.read_number();
        if (sn!=scene_number)
        {
          g1_scene_change_order_event co(eh, g1_scene_editor_class::CHANGE_SCENE_NUMBER,
                                         scene_number, sn);
          i4_kernel.send_event(eh, &co);
        }
      }
      else if (oev->object==scene_name_input)
      {
        CAST_PTR(tev, i4_text_change_notify_event, ev);
        if (cs->name) delete cs->name;
        cs->name=new i4_str(*tev->new_text);
      }
      else if (oev->object==scene_wav_input)
      {
        CAST_PTR(tev, i4_text_change_notify_event, ev);
        if (cs->wave_file) delete cs->wave_file;
        cs->wave_file=new i4_str(*tev->new_text);
      }


    }
    else if (!dialog_active || ev->type()!=i4_event::MOUSE_BUTTON_DOWN)
      i4_parent_window_class::receive_event(ev);
  }

  g1_cut_scene_editor_class(g1_cut_scene_class *cs,                             
                            sw32 scene_number,
                            sw32 start_time,          // in frames
                            i4_graphical_style_class *style,
                            i4_event_handler_class *eh)
    : cs(cs),
      scene_number(scene_number),
      start_time(start_time),
      style(style),
      i4_parent_window_class(0,0),
      eh(eh)
  {
    dialog_active=0;

    w32 l,r,t,b,xon=0;
    style->get_in_deco_size(l,t,r,b);

    i4_font_class *f=style->font_hint->normal_font;
    //resize(300, f->largest_height()+t+b+2);

    i4_str *fn=g1_ges("frame_format").sprintf(10,scene_number);

    scene_number_input=new i4_text_input_class(style,*fn,24,4, this);
    add_child(xon,0, scene_number_input); xon+=scene_number_input->width();

    xon+=tbox_width()*2;

    i4_text_window_class *tw=new i4_text_window_class(*cs->name,style);
    

    scene_name_input=new i4_text_input_class(style,*cs->name,name_width(), 100, this);
    add_child(xon, 0, scene_name_input);   xon+=scene_name_input->width();

    i4_str *s=cs->wave_file;
    if (!s)     
      scene_wav_input=new i4_text_input_class(style,g1_ges("null_string"),wav_width(), 100, this);
    else
      scene_wav_input=new i4_text_input_class(style,*s,wav_width(), 100, this);
    add_child(xon, 0, scene_wav_input);  xon+=scene_wav_input->width();

    // delete button
    i4_object_message_event_class *om;
    om=new i4_object_message_event_class(this, DELETE_ME);
    i4_image_class *del_icon=g1_editor_instance.delete_icon;
    i4_button_class *del=new i4_button_class(&g1_ges("delete_scene_help"),
                                             new i4_image_window_class(del_icon),
                                             style,
                                             new i4_event_reaction_class(this, om));
    del->set_popup(i4_T);
    add_child(xon, 0, del); xon+=del->width();

    resize(xon,f->largest_height()+t+b+2);

  }

  void draw_time_box(sw32 x, sw32 y, 
                     sw32 t, sw32 wid,
                     i4_draw_context_class &context)
                     
  {
    sw32 t_sec=t/G1_MOVIE_HZ;
    sw32 t_usec=(t-t_sec*G1_MOVIE_HZ)*60/G1_MOVIE_HZ;
    w32 l,r,top,b;

    style->get_in_deco_size(l,top,r,b);
    style->draw_in_deco(local_image, x,y, x+wid-1, height()-1, i4_F, context);
    local_image->bar(x+l,y+top, x+wid-r, y+height()-b, 
                     style->color_hint->window.passive.medium,
                     context);

    i4_str *s=g1_ges("time_format").sprintf(30, t_sec, t_usec);
    i4_font_class *f=style->font_hint->normal_font;

    f->set_color(style->color_hint->text_foreground);
    f->put_string(local_image, x+l, y+top+1,  *s, context);
    delete s;
  }


  void parent_draw(i4_draw_context_class &context)
  {
    local_image->clear(style->color_hint->window.passive.medium, context);

    draw_time_box(scene_number_input->width(), 0, start_time, tbox_width(), context);
    draw_time_box(scene_number_input->width()+tbox_width(), 0, cs->total_frames(),
                  tbox_width(), context);       
  }

};



void g1_scene_editor_class::show(i4_parent_window_class *parent_window,
                                 g1_movie_flow_class *_movie,
                                 i4_graphical_style_class *_style)
                                 
{
  movie=_movie;
  style=_style;

  if (parent.get())
    hide();

  i4_color_window_class *holder=new i4_color_window_class(0,0,0, style);

  w32 t=0;
  i4_window_class *addt=new i4_text_window_class(g1_ges("new"), style);
  i4_event_reaction_class *add_reaction;
  i4_event *add_event=new i4_object_message_event_class(this, ADD_SCENE);
  add_reaction=new i4_event_reaction_class(this, add_event);
  i4_button_class *addb=new i4_button_class(0, addt, style, add_reaction);
  addb->set_popup(i4_T);
  holder->add_child(0,0, addb);


  for (w32 i=0; it_cut_scenes; i++)
  {    
    g1_cut_scene_editor_class *ce=new g1_cut_scene_editor_class(movie->set[i], i+1,t, style, this);
    t+=movie->set[i]->total_frames();

    holder->add_child(0,0, ce);
  }

  holder->arrange_right_down();
  holder->resize_to_fit_children();

  w32 w=holder->width(), h=holder->height();

  i4_event_reaction_class *re;
  re=new i4_event_reaction_class(this, new i4_object_message_event_class(this, WINDOW_CLOSED));
  parent=style->create_mp_window(wx, wy, w,h, g1_ges("scene_win_title"), re);

  holder->transfer_children(parent.get(), 0,0);
  delete holder;
                            
}

void g1_scene_editor_class::hide()
{
  if (parent.get())
  {
    if (parent->get_parent())
    {
      wx=parent->get_parent()->x();
      wy=parent->get_parent()->y();
    }

    style->close_mp_window(parent.get());

    parent=0;
  }
}


void g1_scene_editor_class::last_scene()
{
 
  if (movie->t_cut_scenes==1)
    movie->set_scene(0);
  else
  {
    if (movie->get_scene()!=0)
      movie->set_scene(movie->get_scene()-1);
  }
}

void g1_scene_editor_class::receive_event(i4_event *ev)
{
  CAST_PTR(oev, i4_object_message_event_class, ev);
  if (ev->type()==i4_event::OBJECT_MESSAGE)
  {
    if (oev->object==this)
    {
      switch (oev->sub_type)
      {
        case ADD_SCENE :
        {
          g1_editor_instance.add_undo(G1_MAP_MOVIE);

          i4_parent_window_class *parent_window=0;

          if (parent.get() && parent->get_parent() && parent->get_parent()->get_parent())
            parent_window=parent->get_parent()->get_parent();

          hide();
          g1_cut_scene_class *cs=movie->add_cut_scene(g1_ges("new_scene"));
          show(parent_window, movie, style);

          g1_editor_instance.changed();
        } break;

        case WINDOW_CLOSED :
        {
          parent=0;
        } break;

        case CHANGE_SCENE_NUMBER :
        {
          g1_editor_instance.add_undo(G1_MAP_MOVIE);

          i4_parent_window_class *parent_window=0;
          if (parent.get() && parent->get_parent() && parent->get_parent()->get_parent())
            parent_window=parent->get_parent()->get_parent();

          hide();

          CAST_PTR(co, g1_scene_change_order_event, ev);
          co->n--;
          co->o--;

          if (co->n>=movie->t_cut_scenes)
            co->n=movie->t_cut_scenes-1;
          else if (co->n<0)
            co->n=0; 

          sw32 i;
          g1_cut_scene_class *c=movie->set[co->o];
          for (i=co->o; it_cut_scenes-1; i++)
            movie->set[i]=movie->set[i+1];

          for (i=movie->t_cut_scenes-1; i>co->n; i--)
            movie->set[i]=movie->set[i-1];
          
          movie->set[co->n]=c;

          show(parent_window, movie, style);

          g1_editor_instance.changed();
        } break;

        case DELETE_SCENE :
        {
          g1_editor_instance.add_undo(G1_MAP_MOVIE);
    
          i4_parent_window_class *parent_window=0;
          if (parent.get() && parent->get_parent() && parent->get_parent()->get_parent())
            parent_window=parent->get_parent()->get_parent();

          hide();

          CAST_PTR(dev, g1_delete_scene_event_class, ev);
          dev->sn--;

          last_scene();
          g1_cut_scene_class *c=movie->set[dev->sn];
          
          for (w32 i=dev->sn; it_cut_scenes-1; i++)
            movie->set[i]=movie->set[i+1];

          movie->t_cut_scenes--;

          delete c;

          show(parent_window, movie, style);

          g1_editor_instance.changed();
        } break;

      }
    }
  }
}