#include "sopnamsp.h"
#include "piacmd.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>


#include "pdlmgr.h"
#include "ctimer.h"
#include "strutil.h"
#include "strutilxx.h"
// #include "dlftypes.h"
#include "srandgen.h"

#include "pistdimgapp.h"
#include "nobjmgr.h"

// Les differentes classes CommandExecutor
#include "basexecut.h"
#include "graphexecut.h"
#include "piafitting.h"
#include "pawexecut.h"
#include "cxxexecutor.h"
#include "cxxexecwin.h"
#include "contmodex.h" 
#include "flowmodex.h"

#include PISTDWDG_H 
#include PILIST_H 

// ------------------------------------------------------------
//         Gestion d'une fenetre d'aide interactive  
//                    Classe   PIAHelpWind   
// ------------------------------------------------------------

#define HGRPMSGOFFSET  100000

class PIAHelpWind : public PIWindow {
public :
		PIAHelpWind(PIStdImgApp* par, PIACmd* piacmd);
  virtual	~PIAHelpWind();
  virtual void  Show();
  virtual void  Process(PIMessage msg, PIMsgHandler* sender, void* data=NULL);
  inline  void  AddHelpGroup(const char * hgrp, int gid)
                    { hgrpom->AppendItem(hgrp, HGRPMSGOFFSET+gid); }
  inline  void  AddHelpGroup(string const & hgrp, int gid)
                    { hgrpom->AppendItem(hgrp.c_str(), HGRPMSGOFFSET+gid); }
  inline  void  ClearHelpList() 
                    { mNitem=0; hitemlist->DeleteAllItems(); }
  inline  void	AddHelpItem(const char * hitem) 
		    { mNitem++;  hitemlist->AppendItem(hitem, 100+mNitem); }
  inline  void  SetHelpTextLabel(string const & htxt, string const & hlab)
                    { mTxt->SetText(htxt); mLab->SetLabel(hlab); }

protected :
  PIStdImgApp* dap;
  PIACmd* piac;
  int mNitem;
  PIList* hitemlist;
  PIOptMenu* hgrpom;
  PIButton * mBut;
  PILabel * mLab;
  PIText* mTxt;
};

/* --Methode-- */
PIAHelpWind::PIAHelpWind(PIStdImgApp *par, PIACmd* piacmd)
  : PIWindow((PIMsgHandler *)par, "Help-PIApp", PIWK_normal,  400, 300, 100, 350)
{
dap = par;
piac = piacmd;
mNitem = 0;
SetMsg(77);

int bsx, bsy;
int tsx, tsy;
int spx, spy;
PIApplicationPrefCompSize(bsx, bsy);
spx = bsx/6;   spy = bsy/6;
tsx = 10*bsx+2*spx;  tsy = 7*bsy+3*spy;
SetSize(tsx,tsy);
hgrpom = new PIOptMenu(this, "hgrpoptmen", bsx*2.0, bsy, spx/2, spy);
hgrpom->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
hitemlist = new PIList(this, "hitemlist", bsx*2.0, tsy-3*spy-bsy, spx/2, 2*spy+bsy);
hitemlist->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
// hitemlist->SetBorderWidth(2);
mTxt = new PIText(this, "helptext", true, true, bsx*8.0, 6*bsy, bsx*2.0+1.5*spx, spy);
// mTxt->SetMutiLineMode(true);
mTxt->SetTextEditable(false);
mTxt->SetText("");
mTxt->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mLab = new PILabel(this, "helpitem", bsx*4, bsy, bsx*2.5+2*spx, tsy-spy-bsy);
mLab->SetBorderWidth(1);
mLab->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mLab->SetLabel("");
mBut = new PIButton(this, "Close", 70, bsx, bsy, tsx-bsx*1.5-spx, tsy-spy-bsy);
mBut->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
}

/* --Methode-- */
PIAHelpWind::~PIAHelpWind()
{
delete hgrpom;
delete hitemlist;
delete mTxt;
delete mLab;
delete mBut;
}

/* --Methode-- */
void PIAHelpWind::Process(PIMessage msg, PIMsgHandler* sender, void* /*data*/)
{
PIMessage um = UserMsg(msg);
if (((um == 77) && (ModMsg(msg) == PIMsg_Close)) || (um == 70) ) {
  Hide();
  return;
  }
else if ( (um >= HGRPMSGOFFSET) && (sender == hgrpom)) {  // Selection de groupe de Help
  mTxt->SetText("");
  mLab->SetLabel("");
  piac->UpdateHelpList(this, um-HGRPMSGOFFSET);
}
else if ( (um > 100) && (sender == hitemlist) && (ModMsg(msg) == PIMsg_Select) ) {
  string s = hitemlist->GetSelectionStr();
  mTxt->SetText(piac->GetUsage(s));
  mLab->SetLabel(s);
  }  
}

/* --Methode-- */
void PIAHelpWind::Show()
{
hgrpom->SetValue(HGRPMSGOFFSET);   // Groupe All
mTxt->SetText("");
mLab->SetLabel("");
piac->UpdateHelpList(this, 0); 
PIWindow::Show();
}


// ------------------------------------------------------------
//         Classe PIACmd
// ------------------------------------------------------------

// static PIACmd* curpiacmd = NULL;
/* --Methode-- */
PIACmd::PIACmd(PIStdImgApp* app)
  : Commander()
{
mObjMgr = new NamedObjMgr; 
mImgApp = app;
helpwin = new PIAHelpWind(app, this);
helpwin_initdone = false;

string grp = "PIACmd";
string gdesc = "piapp interpreter (class PIACmd) additional builtin commands";
AddHelpGroup(grp, gdesc);

string kw = "exitpiapp";
string usage = "To end the piapp session ";
RegisterCommand(kw, usage, NULL, grp);
kw = "helpwindow";
usage = "To display the Help window ";
RegisterCommand(kw, usage, NULL, grp);
kw = "stop";
usage = "To stop (break) interpreter (PIACmd/Commander) execution";
RegisterCommand(kw, usage, NULL, grp);

basexec = new PIABaseExecutor(this, mObjMgr, app);
graphexec = new PIAGraphicExecutor(this, mObjMgr, app);
fitexec = new PIAFitter(this, app);
pawexec = new PAWExecutor(this, app);
CxxExecutor * cxxe = new CxxExecutor(this, app);
cxxexec = cxxe;

ContModExecutor *cntxx = new ContModExecutor(this, app);//_OP_
cntexec = cntxx; //_OP_
FlowModExecutor *flwxx = new FlowModExecutor(this, app);//_OP_
flwexec = flwxx; //_OP_

cxxoptwin = new  CxxOptionWind(app, cxxe);
cxxexwin  = new  CxxExecWind(app, cxxe);

InitializeHelpWindowMenu();
// <ZThread>  Thread control attributes
fg_thrstop = false;
fg_threxe = false; 
}

/* --Methode-- */
PIACmd::~PIACmd()
{
delete mObjMgr;
delete helpwin;
delete cxxexwin;
delete cxxoptwin;
delete basexec;
delete graphexec;
delete fitexec;
delete pawexec;
delete cxxexec;
}


/* --Methode-- */
void PIACmd::AddInputLine(string const & line)
{
  if (line == "stop")  { 
    StopExecution();
    return;
  }
  mutx_inps.lock();
  inputlines.push(line);   // Ajout d'un element en fin de queue
  mutx_inps.unlock();
  mutx_inps.broadcast();
}

/* --Methode-- */
void PIACmd::StopThread()
{
  fg_thrstop = true;
  mutx_inps.broadcast();
}

/* --Methode-- */
void PIACmd::run()
{
  while (!fg_thrstop) {
    mutx_inps.lock();
    while (inputlines.empty()) { 
      fg_threxe = false;
      mutx_inps.wait();
    }
    string line = inputlines.front();   // On recupere l'element de tete
    inputlines.pop();    // On supprime l'element de tete
    fg_threxe = true;
    mutx_inps.unlock();
    try {
      Interpret(line);
    }
    catch (PThrowable& pex) {  // Catching SOPHYA exceptions 
      cerr << "PIACmd::run() SOPHYA exception in call to Interpret(" << line << ")\n"
           << (string)typeid(pex).name() << " Msg= " << pex.Msg() << endl;
    }
    catch (std::exception& sex) {
      cerr << "PIACmd::run() std::exception in call to Interpret(" << line << ")\n"
           << (string)typeid(sex).name() << " Msg= " << sex.what() << endl;
    }
    catch (...) {
      cerr << "PIACmd::run() unknown exception (...) in call to Interpret(" 
           << line << ")" << endl; 
    }
  }
}

/* --Methode-- */
bool PIACmd::CheckHelpGrp(string& grp, int& gid, string& desc)
{
bool fgnewgrp = Commander::CheckHelpGrp(grp, gid, desc);
if (helpwin_initdone && fgnewgrp) helpwin->AddHelpGroup(grp.c_str(), gid);
return fgnewgrp;
}

/* --Methode-- */
void PIACmd::UpdateHelpList(PIAHelpWind* hw, int gid)
{
helpwin->ClearHelpList();
if (gid == 0) { 
  string htxt = "All registered commands";
  string hlab = "All (HelpGroup)";
  helpwin->SetHelpTextLabel(htxt, hlab);
}
else { 
  CmdHGroup::iterator ith;
  for(ith = cmdhgrp.begin(); ith != cmdhgrp.end(); ith++) {
    if ((*ith).second.gid == gid) {
      string hlab = (*ith).first;
      hlab += " (HelpGroup)";
      helpwin->SetHelpTextLabel((*ith).second.desc, hlab);
      break;
    }
  } 
}
CmdExmap::iterator it;
for(it = helpexmap.begin(); it != helpexmap.end(); it++) {
  if ( (gid != 0) && ((*it).second.group != gid) ) continue;
  helpwin->AddHelpItem((*it).first.c_str());
  }
for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
  if ( (gid != 0) && ((*it).second.group != gid) ) continue;
  helpwin->AddHelpItem((*it).first.c_str());
  }
}

/* --Methode-- */
void PIACmd::InitializeHelpWindowMenu()
{
  helpwin->AddHelpGroup("All", 0);
  CmdHGroup::iterator it;
  for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) 
    helpwin->AddHelpGroup((*it).first, (*it).second.gid);
  helpwin_initdone = true;
}

/* Fonction */
static string GetStringFrStdin(PIACmd* piac)
{
PIStdImgApp* piapp = piac->GetImgApp();
if (piapp) {
  PIBaseWdg* wdg = piapp->CurrentBaseWdg();
  if (wdg)  wdg->Refresh();
}
char buff[128];
fgets(buff, 128, stdin);
buff[127] = '\0';
return((string)buff);
}

/* --Methode-- */
bool PIACmd::GetVarApp(string const & vn, string & vv)
{
  vv = "";
  if (mObjMgr == NULL) return false;
  vector<string> opts;
  SplitStringToVString(vn, opts, '.');
  string nom = opts[0];
  opts.erase(opts.begin());
  NObjMgrAdapter* obja = mObjMgr->GetObjAdapter(nom);
  if (obja == NULL) return false;
  vv = obja->GetInfoString(opts);
  return true;
}

/* --Methode-- */
int PIACmd::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
{
int rc = 0;
NamedObjMgr omg;

// >>>>>>>>>>> Commande d'interpreteur
if ( (kw == "helpwindow") && (mImgApp))  { 
  ZSync zs(mImgApp->getMutex());
  ShowHelpWindow();
  zs.NOp();
  return 0;
}
// ----> Sortie d'application
else if ((kw == "exitpiapp") && (mImgApp)) {
  mImgApp->Stop();
  return 0;
}
else return Commander::ExecuteCommandLine(kw, tokens, toks);
return 0;
}


/* --Methode-- */
void PIACmd::ShowHelpWindow()
{
  helpwin->Show();
}

/* --Methode-- */
void PIACmd::ShowCxxOptionWindow()
{
  cxxoptwin->Show();
}

/* --Methode-- */
void PIACmd::ShowCxxExecWindow()
{
  cxxexwin->Show();
}

/* --Methode-- */
void PIACmd::SetCurrentPrompt(const char* pr)
{
  Commander::SetCurrentPrompt(pr);
  if (mImgApp) { 
    ZSync zs(mImgApp->getMutex()); zs.NOp(); 
    mImgApp->GetConsole()->SetPrompt(pr);
  }
}

/* --Methode-- */
void PIACmd::ShowMessage(const char * msg, int att)
{
  /*
  Il faut faire quelque chose pour gerer correctement ca en multithread
  char va = (att == 0) ? 0 : PIVA_Magenta;
  if (mImgApp) { 
    ZSync(mImgApp->getMutex()); zs.NOp(); 
    mImgApp->GetConsole()->AddStr(msg, va);
  }
  */
Commander::ShowMessage(msg, att);
}


/* --Methode-- */
SOpExObj::SOpExObj(PIStdImgApp* app)
{
  mImgApp = app;
  fg_thrstop = false;
  fg_threxe = false;
}

/* --Methode-- */
SOpExObj::~SOpExObj()
{
}

/* --Methode-- */
void SOpExObj::AddOpe(string const & line)
{
  mutx_inps.lock();
  inputlines.push(line);   // Ajout d'un element en fin de queue
  mutx_inps.unlock();
  mutx_inps.broadcast();
}

/* --Methode-- */
void SOpExObj::run()
{
  NamedObjMgr omg;
  while (!fg_thrstop) {
    mutx_inps.lock();
    while (inputlines.empty()) { 
      fg_threxe = false;
      mutx_inps.wait();
    }
    string cmd = inputlines.front().substr(0,3);   // On recupere l'element de tete
    string nom = inputlines.front().substr(4);   // On recupere l'element de tete
    inputlines.pop();    // On supprime l'element de tete
    fg_threxe = true;
    mutx_inps.unlock();
    try {
      if (cmd == "UPD") {  // UpdateObjMgrWindow()
	int did = atoi(nom.c_str());
	omg.UpdateObjMgrWindow(did);
      }
      else if (cmd == "SCO") {  // set cobj 
	string ss = "set cobj ";
	ss += nom;
	cout << " Defining cobj : " << ss << endl;
	mImgApp->CmdInterpreter()->AddInputLine(ss);
      }
      else if (cmd == "DIS") {  // display obj
	omg.DisplayObj(nom);
      }
      else if (cmd == "PRT") {  // print obj
	omg.PrintObj(nom);
      }
      else if (cmd == "DEL") {  // delete obj
	omg.DelObj(nom);
      }
      else if (cmd == "SAV") {  // saveppf obj
	if (mImgApp->mPpfout)  omg.SaveObj(nom, *(mImgApp->mPpfout), false);
      }
      else cerr << "SOpExObj::run() ERROR CMD= " << cmd << endl; 
    }
    catch (PThrowable& pex) {  // Catching SOPHYA exceptions 
      cerr << "SOpExObj::run() SOPHYA exception CMD=" << cmd << " NOM=" << nom << "\n"
           << (string)typeid(pex).name() << " Msg= " << pex.Msg() << endl;
    }
    catch (std::exception& sex) {
      cerr << "SOpExObj::run() std::exception CMD=" << cmd << " NOM=" << nom << "\n"
           << (string)typeid(sex).name() << " Msg= " << sex.what() << endl;
    }
    catch (...) {
      cerr << "SOpExObj::run() unknown exception (...) CMD=" 
	   << cmd << " NOM=" << nom << endl;
    }
  }
}
