/**********************************************************************
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/mode/e_mode.hh"
#include "editor/contedit.hh"
#include "window/wmanager.hh"
#include "window/win_evt.hh"
#include "device/kernel.hh"
#include "window/style.hh"
#include "g1_render.hh"
#include "g1_limits.hh"
#include "r1_api.hh"
#include "app/app.hh"
#include "resources.hh"
#include "editor/e_state.hh"
#include "editor/editor.hh"
#include "lisp/lisp.hh"
#include "lisp/li_init.hh"

sw32 g1_mode_handler::lx() { return c->last_mouse_x; }
sw32 g1_mode_handler::ly() { return c->last_mouse_y; }

sw32 g1_mode_handler::x() { return c->x(); }
sw32 g1_mode_handler::y() { return c->y(); }


g1_mode_creator *g1_mode_creator::first=0;

void g1_mode_handler::uninit()
{
}

i4_bool g1_mode_handler::active()
{
  return c->active();
}

g1_mode_creator::g1_mode_creator()
{
  minor_mode=0;
  next=first;
  first=this;
}

g1_mode_creator::~g1_mode_creator()
{
  if (first==this)
    first=first->next;
  else
  {
    g1_mode_creator *last=0;
    for (g1_mode_creator *f=first; f!=this;)
    {
      last=f;
      f=f->next;
    }
    last->next=next;
  }
} 


i4_graphical_style_class *g1_mode_creator::get_style()
{
  return i4_current_app->get_style();
}

i4_transform_class *g1_mode_handler::get_transform()
{
  return &c->transform;
}

g1_mode_handler::g1_mode_handler(g1_controller_edit_class *c) 
  : c(c) 
{
  mouse_down_flag=i4_F;
  
  drag=i4_F;
  drag_select=i4_F;
  cursor_type=G1_DEFAULT_CURSOR;
}

void g1_mode_handler::update_cursor()
{
  float x,y,z;
  w8 nc=G1_DEFAULT_CURSOR;
  
 

  if (g1_map_is_loaded() && current_state()==DRAG_SELECT) 
  {
    if (drag)
      nc=G1_MOVE_CURSOR;
    else if (select_object(lx(), ly(), x,y,z, FOR_CURSOR_HINT))
      nc=G1_SELECT_CURSOR;
  }

  if (nc!=cursor_type)
  {
    cursor_type=nc;
    c->set_cursor(g1_resources.big_cursors[cursor_type]);
  }
}


void g1_mode_handler::mouse_move(sw32 mx, sw32 my)
{
  switch (current_state())
  {
    case DRAG_SELECT :
    {
      if (drag)   // are we dragging game stuff around?
      {
        i4_transform_class *t=&c->transform;

        i4_3d_point_class control_point;   

        t->transform(pos, control_point);

        i4_3d_vector is(1,0,0), js(0,1,0), center, i,j;
        t->inverse_transform(i4_3d_vector(0,0,0), center);
        t->inverse_transform(is, i);
        i-=center;
        t->inverse_transform(js, j); 
        j-=center;

        // i & j now for the camera plane

        i4_float csx=g1_render.scale_x;
        i4_float csy=g1_render.scale_y;



        i4_float sx=(mx-lx())/(csx*g1_render.center_x) * control_point.z;
        i4_float sy=(my-ly())/(csy*g1_render.center_y) * control_point.z;
    

        i*=sx;
        j*=sy;
   
        i4_float xc=i.x+j.x, yc=i.y+j.y, zc=i.z+j.z;

        pos.x+=xc; pos.y+=yc; pos.z+=zc;
        i4_3d_point_class current_snap_pos=pos;
        g1_edit_state.snap_point(current_snap_pos);

        move_selected(current_snap_pos.x-snap_pos.x,
                      current_snap_pos.y-snap_pos.y,
                      current_snap_pos.z-snap_pos.z,
                      mx-lx(), my-ly());    

        snap_pos=current_snap_pos;
      }
      else if (mouse_down_flag && drag_select)
      {
        sx2=mx;
        sy2=my;
        c->request_redraw();
      }
    } break;
    
    case ZOOM :
      if (mouse_down_flag)
        if (i4_current_app->get_window_manager()->shift_pressed())
          c->rotate((mx-lx())*0.01, (ly()-my)*0.01);
        else
          c->zoom((ly()-my)/50.0);
      
      break;
      
    case ROTATE :
      if (mouse_down_flag)
        if (i4_current_app->get_window_manager()->shift_pressed())
          c->zoom((ly()-my)/50.0);
        else
          c->rotate((mx-lx())*0.01, (ly()-my)*0.01);
          break; 
  }
}

void g1_mode_handler::mouse_up()
{
  if (mouse_down_flag)
  {
    ungrab_mouse();

    if (drag)
    {
      update_cursor();
      drag=i4_F;
    }
    else if (current_state()==DRAG_SELECT && drag_select)
    {
      sw32 dx1,dy1,dx2,dy2;
      if (sx1get_window_manager()->shift_pressed())
        mod=ADD_TO_OLD;
      else if (i4_current_app->get_window_manager()->alt_pressed())
        mod=SUB_FROM_OLD;
      else
        mod=CLEAR_OLD_IF_NO_SELECTION;

      select_objects_in_area(dx1,dy1,dx2,dy2, mod);
      c->request_redraw();
      drag_select=i4_F;
      update_cursor();
    }

  }
}

void g1_mode_handler::grab_mouse()
{
  mouse_down_flag=i4_T;
}

void g1_mode_handler::ungrab_mouse()
{
  mouse_down_flag=i4_F;
}

void g1_mode_handler::do_command(i4_do_command_event_class *cmd)
{
  if (!strcmp(cmd->command, "edit_selected"))
    edit_selected();  
}

void g1_mode_handler::end_command(i4_end_command_event_class *cmd)
{
  
}


void g1_mode_handler::mouse_down()
{ 
  grab_mouse();

  if (current_state()==DRAG_SELECT)
  {
    select_modifier mod;
    if (i4_current_app->get_window_manager()->shift_pressed())
      mod=ADD_TO_OLD;
    else if (i4_current_app->get_window_manager()->alt_pressed())
      mod=SUB_FROM_OLD;
    else
      mod=CLEAR_OLD_IF_NO_SELECTION;


    if (select_object(lx(), ly(), pos.x, pos.y, pos.z, mod))
    {
      snap_pos=pos;
      i4_time_class now;
      if (now.milli_diff(last_click_time)style->time_hint->double_click)
        edit_selected();
      else
        drag=i4_T;
    }
    else
    {
      drag_select=i4_T;
      sx2=sx1=lx();
      sy2=sy1=ly();
    }

    update_cursor();
  }

  last_click_time.get();
}

void g1_mode_handler::post_draw(i4_draw_context_class &context)
{
  if (current_state()==DRAG_SELECT && mouse_down_flag && !drag)
    g1_render.draw_rectangle(sx1,sy1,sx2,sy2, 0xffffff, context);
}

i4_bool g1_mode_handler::pass_through_focus_click()
{
  switch (current_state())
  {
    case ZOOM :
    case ROTATE : return i4_T; break;
  }
  return i4_F;
}


li_object *g1_delete_selected(li_object *o, li_environment *env)
{
  g1_controller_edit_class *v=g1_editor_instance.get_current_view();
  if (v)
  {
    v->get_mode()->delete_selected();
    return li_true_sym;
  }
  
  return 0;
}

li_automatic_add_function(g1_delete_selected, "Map/Delete Selected");