#include "ba0103.h"

#include <applicat.h>
#include <config.h>
#include <controls.h>
#include <defmask.h>
#include <dongle.h>
#include <execp.h>
#include <utility.h>

enum { DLG_TREE = 101, DLG_LOOK = 102, DLG_MAIN = 103 };

///////////////////////////////////////////////////////////
// TApp_window & TBook_window declarations
///////////////////////////////////////////////////////////

class TBook_window;

class TApp_window : public TWindow
{
  TBook_window* _owner;
  TString _appname;

protected:
  virtual long handler(WINDOW win, EVENT* ep);

public:
  const TString& app_name() const { return _appname; }

  TApp_window(TBook_window* owner, const char* appname);
  ~TApp_window();
};

class TBook_window : public TControl_host_window
{
  TImage _logo;

protected:
  virtual void update();
  virtual long handler(WINDOW win, EVENT* ep);

  void force_page(short page);
  void erode_antipa();

public:
  WINDOW notebook() const { return _ctrl; }
  short pages() const;
  short curr_page() const;
  WINDOW page_win(short pg);
  short add_page(const TMenuitem& mi);
  void set_page_caption(short page, const TString& caption, int icon);
  bool remove_page(WINDOW page);
  void set_logo(const char* logo);
  
  TBook_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
  ~TBook_window();
};

///////////////////////////////////////////////////////////
// TApp_window
///////////////////////////////////////////////////////////

long TApp_window::handler(WINDOW win, EVENT* ep)
{
  switch (ep->type)
  {
  case E_TIMER:
    if (xvt_vobj_is_focusable(win))
    {
      // Leggo il titolo della finestra corrente
      TString256 title;
      xvt_vobj_get_title(win, title.get_buffer(), title.size());
      // Se la finestra ospita gia' un'applicazione non si chiama piu' "__CAMPO_HOST_WINDOW__"
      if (title != __MAGIC_CAPTION__) 
      {
        if (xvt_win_get_children_count(win) == 0) // Se l'applicazione e' morta ...
        {
          xvt_timer_destroy(ep->v.timer.id);      // Ammazzo il timer ...
          _owner->remove_page(win);               // ... e pure la pagina ospitante
        }
      }
    }
    break;
  case E_DESTROY:
    xvt_sys_close_children(win);
    break;
  default:
    break;
  }
  return TWindow::handler(win, ep);
}

TApp_window::TApp_window(TBook_window* owner, const char* appname) : _owner(owner), _appname(appname)
{
  WINDOW w = create(0, 0, -1, -1, __MAGIC_CAPTION__, WSF_NONE, W_PLAIN, owner->notebook());
  xvt_timer_create(w, 1000); // Ogni tanto controllo che l'applicazione sia ancora viva
}

TApp_window::~TApp_window() 
{
  xvt_sys_close_children(win());
}

///////////////////////////////////////////////////////////
// TBook_window
///////////////////////////////////////////////////////////

void TBook_window::update()
{
  // Disegno lo sfondo solo se non esiste nessun notebook che occupa tutto lo spazio!
  if (_ctrl == NULL_WIN)
  {
    clear(NORMAL_BACK_COLOR);
    RCT rctw; xvt_vobj_get_client_rect(win(), &rctw);
    if (rctw.right >= 64 && rctw.bottom >= 64)
    {
      if (_logo.ok())
        _logo.draw(win(), rctw, 'C', 'B', '-'); // Disegna logo riducendolo al centro in basso
      const PNT pnt = { 0, 0 };
      draw_spider(win(), 0x3, pnt);
    }
  }
}

short TBook_window::pages() const
{
  return _ctrl == NULL_WIN ? 0 : xvt_notebk_get_num_tabs(_ctrl);
}

short TBook_window::curr_page() const
{
  return _ctrl == NULL_WIN ? 0 : xvt_notebk_get_front_page(_ctrl);
}

static BOOLEAN hell_riser(WINDOW child, long data)
{
  if (data > 0)
    xvt_vobj_raise(child);
  xvt_win_enum_wins(child, hell_riser, data+1, 0);
  return TRUE;
}

void TBook_window::force_page(short page)
{
  if (page < pages()) // Implies _ctrl != NULL_WIN too
  {
    xvt_notebk_set_front_page(_ctrl, page);
    WINDOW w = xvt_notebk_get_page(_ctrl, page);
    xvt_win_enum_wins(w, hell_riser, 0, 0);
  }
}

long TBook_window::handler(WINDOW win, EVENT* ep)
{
  switch (ep->type)
  {
  case E_MOUSE_MOVE:
    if (_ctrl == NULL_WIN)
      draw_spider(win, 0x3, ep->v.mouse.where);
    break;
  case E_CONTROL:
    if (ep->v.ctl.ci.type == WC_NOTEBK && ep->v.ctl.ci.win == _ctrl)
    {
      if (ep->v.ctl.ci.v.notebk.page != NULL_WIN) // != NULL_WIN means page CHANGED, non changing!
        force_page(ep->v.ctl.ci.v.notebk.page_new);
      return 0L;
    }
    break;
  case E_SIZE:
    if (pages() > 0)
      dispatch_e_menu(cur_win(), 8883); // Notifica un ridimensionamento indesiderato
    break;
  default:
    break;
  }
  return TControl_host_window::handler(win, ep);
}

WINDOW TBook_window::page_win(short pg)
{
  WINDOW win = NULL_WIN;
  if (_ctrl != NULL_WIN)
  {
    if (pg < 0) 
      pg = xvt_notebk_get_front_page(_ctrl);
    win = xvt_notebk_get_page(_ctrl, pg);
  }
  return win;
}

short TBook_window::add_page(const TMenuitem& mi)
{
  if (_ctrl == NULL_WIN)
  {
  	XVT_COLOR_COMPONENT xcc[4]; memset(xcc, 0, sizeof(xcc));
		xcc[0].type = XVT_COLOR_BACKGROUND;	xcc[0].color = MASK_BACK_COLOR;
		xcc[1].type = XVT_COLOR_FOREGROUND;	xcc[1].color = NORMAL_COLOR;
   
    WIN_DEF wd; memset(&wd, 0, sizeof(wd));
    wd.wtype = WC_NOTEBK;
    wd.ctlcolors = xcc;
    wd.v.ctl.ctrl_id = DLG_MAIN;
    wd.v.ctl.font_id = xvtil_default_font();
    wd.v.ctl.flags = CTL_FLAG_TAB_BOTTOM;   // should be wxCHECK_VERSION(2,8,9)
    wd.v.ctl.flags |= CTL_FLAG_CENTER_JUST; // old compatibility flags
    
    xvt_vobj_get_client_rect(win(), &wd.rct);
    _ctrl = xvt_ctl_create_def(&wd, win(), 0L);
    // Blocca le dimensioni del pannello (Non va micca!)
    xvt_pane_set_size_range(win(), wd.rct.right, wd.rct.right, wd.rct.right);
    enable_options_menu(false); // Disabilita le opzioni
  }

  for (short pg = pages()-1; pg >= 0; pg--)
  {
    WINDOW awin = xvt_notebk_get_page(_ctrl, pg);
    TApp_window* w = (TApp_window*)xvt_vobj_get_data(awin);
    if (w != NULL && w->app_name() == mi.action())
    {
      force_page(pg);
      return -1;      // Don't perform menu!
    }
  }

  TApp_window* w = new TApp_window(this, mi.action());
  const short pg = xvt_notebk_add_page(_ctrl, w->win(), mi.caption(), NULL, -1);
  if (pg >= 0)
    force_page(pg);
  else
    delete w;
 
  return pg;
}

void TBook_window::set_page_caption(short page, const TString& caption, int icon)
{
  if (_ctrl != NULL_WIN && page >= 0)
  {
    xvt_notebk_set_tab_title(_ctrl, page, caption);  // Titolo dell'orecchio
    xvt_notebk_set_tab_icon(_ctrl, page, icon);      // Icona dell'orecchio
    xvt_notebk_set_page_title(_ctrl, page, caption); // Titolo della finestra
  }
}

bool TBook_window::remove_page(WINDOW page)
{
  bool bFound = false;
  for (int p = pages()-1; p >= 0; p--)
  {
    WINDOW win = xvt_notebk_get_page(_ctrl, p);
    if (win == page || page == NULL_WIN)
    {
      xvt_notebk_rem_page(_ctrl, p);
      bFound = true;
      if (page != NULL_WIN)
        break;
    }
  }
  if (bFound)
  {
    xvt_vobj_raise(TASK_WIN); // Riporta in primo piano il menu principale
    if (pages() == 0)
    {
      erode_antipa();
      force_update();
    }
    else
      force_page(0);
  }
  return bFound;
}

void TBook_window::erode_antipa()
{
  if (_ctrl != NULL_WIN)
  {
    // Ammazza anche tutti ... coloro che son sospesi
    for (int p = pages()-1; p >= 0; p--)
      xvt_notebk_rem_page(_ctrl, p);
    xvt_vobj_destroy(_ctrl); 
    _ctrl = NULL_WIN;
    enable_options_menu(true); // Riabilita le opzioni
  }
}

void TBook_window::set_logo(const char* logo)
{
  _logo.load(logo);
  if (is_power_station())
  {
    const short w = _logo.width();
    const short h = _logo.height(); 
    const short h2 = h/4;
   
    XVT_IMAGE big = xvt_image_create(XVT_IMAGE_RGB, w, h+h2, NORMAL_BACK_COLOR);
    RCT rct; xvt_rect_set(&rct, 0, 0, w, h);
    xvt_image_transfer(big, _logo.xvt_image(), &rct, &rct);
    for (short y = 0; y < h2; y++)
    {
      const double weight = 0.5+double(y)/double(2*h2);
      const short sy = h-y*h/h2-1;
      for (short x = 0; x < w; x++)
      {
        const short sx = x-2*y;
        COLOR col = MASK_DARK_COLOR;
        if (sx >= 0)
        {
          const COLOR rgb = xvt_image_get_pixel(big, sx, sy);
          const unsigned char r = XVT_COLOR_GET_RED(rgb);
          const unsigned char g = XVT_COLOR_GET_GREEN(rgb);
          const unsigned char b = XVT_COLOR_GET_BLUE(rgb);
          if (r != g || g != b)
            col = blend_colors(col, rgb, weight);
        }
        xvt_image_set_pixel(big, x, y+h, col);
      }
    }
    _logo.set(big);
  }
  else
  {
    if (_logo.ok() && can_be_transparent(_logo))
      _logo.convert_transparent_color(NORMAL_BACK_COLOR);
  }
}

TBook_window::TBook_window(int x, int y, int dx, int dy, 
                           WINDOW parent, TWindowed_field* owner)
            : TControl_host_window(x, y, dx, dy, parent, owner), _logo("")
{
  set_logo(get_logo());
}

TBook_window::~TBook_window()
{ erode_antipa(); }

///////////////////////////////////////////////////////////
// TBook_field
///////////////////////////////////////////////////////////

class TBook_field : public TWindowed_field
{
protected:
  virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);

public:
  virtual void create(short dlg, int x, int y, int dx, int dy, WINDOW parent);

  short pages() const;
  short add_page(const TMenuitem& mi);
  void set_page_caption(short page, const TString& caption, int icon);
  WINDOW page_win(short page);
  void remove_all_pages();
  TBook_field(TMask* m) : TWindowed_field(m) {}
};

short TBook_field::pages() const
{
  TBook_window& bw = (TBook_window&)win();
  return bw.pages();
}

short TBook_field::add_page(const TMenuitem& mi)
{
  TBook_window& bw = (TBook_window&)win();
  return bw.add_page(mi);
}

void TBook_field::set_page_caption(short page, const TString& caption, int icon)
{
  TBook_window& bw = (TBook_window&)win();
  bw.set_page_caption(page, caption, icon);
}

WINDOW TBook_field::page_win(short page)
{
  TBook_window& bw = (TBook_window&)win();
  return bw.page_win(page);
}

void TBook_field::remove_all_pages()
{
  TBook_window& bw = (TBook_window&)win();
  bw.remove_page(NULL_WIN);
}

TField_window* TBook_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
{
  return new TBook_window(x, y, dx, dy, parent, this);
}

void TBook_field::create(short dlg, int x, int y, int dx, int dy, WINDOW parent)
{
  _dlg = dlg;
  _win = create_window(x, y, dx, dy, parent);
}

///////////////////////////////////////////////////////////
// TOutlook_mask
///////////////////////////////////////////////////////////

void TOutlook_mask::save_perspective(int per)
{
  const TTree_field& bf = tfield(DLG_TREE);
  TString str(_per_def.size());
  const int sz = xvt_pane_manager_save_perspective(bf.win().win(), NULL, 0); 
  xvt_pane_manager_save_perspective(bf.win().win(), str.get_buffer(sz), sz); 
  switch (per)
  {
  case  1: 
    {
      TConfig ini(CONFIG_GUI, "ba0103");
      ini.set("Layout", str, NULL, true, bf.dlg());
    }
    break;
  case  2: _per_tmp = str; break;
  default: _per_def = str; break;
  }
}

void TOutlook_mask::load_perspective(int per)
{
  const TTree_field& bf = tfield(DLG_TREE);
  TString str;
  switch (per)
  {
  case  1:
    {
      TConfig ini(CONFIG_GUI, "ba0103");
      str = ini.get("Layout", NULL, bf.dlg());
    }
    break;
  case  2: str = _per_tmp; break;
  default: str = _per_def; break;
  }
  xvt_pane_manager_load_perspective(bf.win().win(), str); 
}

bool TOutlook_mask::can_be_closed() const
{
  const bool yes = !is_running();
  if (!yes)
  {
    TBook_field& bf = (TBook_field&)field(DLG_MAIN);
    if (bf.pages() == 0)
      ((TOutlook_mask*)this)->send_key(K_FORCE_CLOSE, 0);
    else
      warning_box(TR("E' necessario chiudere tutte le applicazioni attive"));
  }
  return yes;
}

short TOutlook_mask::add_page(const TMenuitem& mi)
{
  TBook_field& bf = (TBook_field&)field(DLG_MAIN);
  if (bf.pages() == 0)
    save_perspective(2);       // Save temporary perspective
  return bf.add_page(mi);
}

void TOutlook_mask::set_page_caption(short page, const TString& caption, int icon)
{
  TBook_field& bf = (TBook_field&)field(DLG_MAIN);
  bf.set_page_caption(page, caption, icon);
}

long TOutlook_mask::handler(WINDOW w, EVENT* ep)
{
  if (ep->type == E_COMMAND)
  {
    switch (ep->v.cmd.tag)
    {
    case 8001: 
      set(DLG_LOOK, "", true);          // Seleziona menu completo
      break;
    case 8002: 
      load_perspective(0);              // Ricarica default 
      break;
    case 8003: 
      xvt_dm_post_string_prompt(TR("Testo da cercare"), 
                                _last_search.get_buffer(), _last_search.size());
      // continue to 8004
    case 8004: 
      if (_last_search.full() && _tree.find_string(_last_search))
      {
        TTree_field& tf = tfield(DLG_TREE);
        synchronize_tree_field(tf);
        tf.select_current();
      }
      break;
    case 8005: 
      dispatch_e_menu(TASK_WIN, M_FILE_ABOUT);
      break;
    case 8883: 
      if (!_locked && _per_tmp.not_empty())
      {
        _locked = true;
        load_perspective(2); // Ripristina layout predefinito
        do_events();         // Evita doppio evento E_SIZE
        _locked = false;
      }
      break;
    default  : break;
    }
  }
  return TSpidey_mask::handler(w, ep);
}

bool TOutlook_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch (o.dlg())
  {
  case DLG_TREE:
    if (e == fe_button)
    {
      const TMenuitem& mi = _tree.curr_item();
      if (mi.enabled())
      {
        if (mi.is_submenu())
        {
          if (!_tree.expanded())
            mi.perform();
        }
        else
        {
          TBook_field& bf = (TBook_field&)field(DLG_MAIN);
          // ba1 e ba2 sono programmi di manutenzione da eseguire in modo esclusivo
          if (mi.run_modal())                              
          {
            if (bf.pages() > 0)
              return warning_box(TR("Questa applicazione richiede che vengano chiuse tutte le altre!"));
            
            mi.perform();                        // Esegui in sincrono e a tutto schermo
            if (installing())                    // when ba1 -6
              stop_run(K_FORCE_CLOSE);
          } else
          if (mi.run_fullscreen())
          {
            mi.perform(); // Esegui in asincrono a pieno schermo
          }
          else
          {
            // Crea una pagina per accogliere la nuova applicazione asincrona
            const short pg = add_page(mi);
            if (pg >= 0)
            {
  		        mi.perform();                      // Esegui in asincrono in pagina nuova

              for (int i = 0; i < 20; i++)
              {
                xvt_sys_sleep(500);
                if (xvt_win_get_children_count(bf.page_win(pg)) != 0)
                  break;
              }

              int ico = mi.icon();
              if (ico <= 0 || ico == ICON_RSRC)
              {
                const int area = get_int(DLG_LOOK);
                if (area > 0 && area < 16)
                  ico = _icon[area];
                else
                  ico = ICON_RSRC;
              }
              set_page_caption(pg, mi.caption(), ico);
            }
          }
        }
      }
    }
    break;
  case DLG_LOOK:
    if (e == fe_modify)
    {
      TTree_field& tf = tfield(DLG_TREE);
      const int sel = atoi(o.get());
      TToken_string id("MENU_000", '/'); 
      _tree.change_root(id);        // Torna alla radice standard
      if (sel > 0)
      {
        for (int i = 1; i < sel; i++)
        {
          do
            _tree.goto_rbrother();      // Sceglie l'opportuno ramo principale
          while (!_tree.enabled());
        }
        _tree.goto_firstson();
        _tree.curr_id(id);
        _tree.change_root(id.get(1)); // Imposta una nuova radice
        synchronize_tree_field(tf);
      }
      else
      {
        _tree.goto_root();
        _tree.shrink_all();
        tf.win().force_update();
        tf.on_key(K_SPACE);
      }
      main_app().enable_menu_item(30005, id.find("MENU_PREFERITI") < 0);
    } else
    if (e == fe_init)
    {
      TOutlook_field& of = (TOutlook_field&)o;
      of.clear();

      TString caption;
      int i = 0;
      int ico = 10219;
      of.add_item(ico, TR("Menu principale"), 0);
      _icon[i++] = ico;
      TToken_string id("MENU_000", '/'); 
      _tree.change_root(id);        // Torna alla radice standard
      for (bool ok = _tree.goto_root(); ok; ok = _tree.goto_rbrother())
      {
        const TMenuitem& mi = _tree.curr_item();
        if (mi.enabled())
        {
          _tree.get_description(caption);
          const int ico = mi.icon();
          of.add_item(ico, caption, 0);
          _icon[i++] = ico; // Memorizza icona per orecchie
        }
      }
      if (atoi(of.get()) >= of.items()-1) // Se sono sui preferiti ...
        set(o.dlg(), "", true);           // ... torna al menu principale
    }
    break;
  default: break;
  }

  if (e == fe_info)
  {
    MENU_ITEM* mi = xvt_res_get_menu(10004); // Menu_Ba0-3
    if (mi != NULL)
    {
      dictionary_translate_menu(mi);
      const PNT pos = { -1, -1 };
      xvt_menu_popup(mi->child, o.parent(), pos, XVT_POPUP_LEFT_ALIGN, 0);
      xvt_res_free_menu_tree(mi);
      return false; // Non fare la gestione standard
    }
  }

  return true;
}

TOutlook_mask::TOutlook_mask(TMenu& menu) : _tree(menu), _locked(false)
{ 
  xvtil_statbar_destroy(); // Ammazza status bar inutile
  RCT rct; xvt_vobj_get_client_rect(TASK_WIN, &rct);

  WINDOW panel = page_win(0);
  xvt_vobj_move(panel, &rct); // Resiza la maschera in modo da occupare lo spazio liberato

  menu.set_mask_mode(3); // Outlook mode

  const int w = 24;
  const int h = rows() / 2;

  TTree_field& trifola = add_tree(DLG_TREE, 0, 0, 0, w, h);
  trifola.set_tree(&_tree);

  TOutlook_field* of = new TOutlook_field(this);
  of->create(DLG_LOOK, 0, h, w, h, panel); 
  add_field(of);

  TBook_field* cf = new TBook_field(this);
  cf->create(DLG_MAIN, w, 0, 0, 0, panel); 
  add_field(cf);

  xvt_pane_add(panel, dlg2win(DLG_TREE), "Menu", 1, 0); // Left upper pane
  xvt_pane_add(panel, dlg2win(DLG_LOOK), "Aree", 1, 0); // Left lower pane
  xvt_pane_add(panel, dlg2win(DLG_MAIN), "Main", 0, 0); // Main pane
  save_perspective(0); // Salva default
  load_perspective(1); // Carica custom
  set_handlers();
}

TOutlook_mask::~TOutlook_mask()
{
  save_perspective(1);       // Salva custom
  // Ricostruisci status bar tornata utile
  xvtil_create_statbar();
  // Ammazza eventuali processi dormienti in background
  xvt_sys_close_siblings(TASK_WIN);
}