/*\
 *  Autocad ADS library C++ link
 *  $Id: adsapp.cpp 1.1 1994/11/09 11:24:06 leon Exp leon $
\*/


// #define ADSDEBUG


#include <algo.h> // stl

#include "adsapp.hpp"

#include <string.h>


ADSFunction::ADSFunction(void (*pFunc)(), const char *name, short number)
   : name(name), number(number), pFunc(pFunc){}

/**
 ** Na zahtevo sistema nalozi funkcije, ki smo jih registrirali s
 ** funkcijo Register. Funkcija je vitrualna in jo lahko uporabimo
 ** za zagon svojih funkcij, ki naj bi se izvedle ob zagonu z ukazom
 ** (xload "file.exp")
 **/
short ADSApplication::load()
{
  for (short i = 0; i < total; i++)
  fArray[i].load();
  return RTNORM;
};

/**
 ** Podobno kot funkcija load() se ta izvede, ko sistem zahteva
 ** brisanje aplikacije iz spomina. Funkcije se brisejo. Uporabnik
 ** pa lahko prepise (overloada) funkcijo s svojo, da pobrise za sabo
 ** vsa globalna polja, neshranjene podatke in podobno.
 **/
short ADSApplication::unload()
{
  for (short i = 0; i < total; i++)
    fArray[i].unload();
  return RTNORM;
};

/**
 ** Ko sistem AutoCad dobi ustrezen ukaz od Lisp-a se ugotovi, katera
 ** funkcija je to bila in jo izvrsi.
 **/
short ADSApplication::execute()
{
  int val;
  if ((val = ads_getfuncode ()) < 0)
    return 0;
  fArray[val].execute();
  return RTNORM;
}


/**
 ** Registrira funkcijo /func/ z imenom /funcName/ katerega lahko
 ** odtipkamo v ukazni vrstici.
 **/
void ADSApplication::Register(void (*func)(), const char *funcName)
{
  fArray.push_back(ADSFunction(func, funcName, total++));
}

/**
 ** Registrira aplikacijo  z imenom /appName/, da jo lahko uporabimo
 ** pri graditvi XDATA.
 **/
void ADSApplication::Register(const char *appName)
{
  struct resbuf *rb;
  if ((rb = ads_tblsearch("APPID", appName, 0)) == NULL)
    {
      if (ads_regapp(appName) != RTNORM)
        ads_printf("Can't register XDATA for %s.\n", appName);
    }
  else
    ads_relrb(rb);
}            
/**
 ** Glavna funkcija za zagon aplikacije, ki vsebuje zanko za
 ** komunikacijo z AutoLispom. Argumenti /argc/ in /argv/ so
 ** isti kot pri funkciji main(int argc, char *argv[])
 **/
void ADSApplication::Run(int argc, char *argv[])
{
  int scode = RSRSLT;		// Normal result code (default) 

  int stat;
  ads_init (argc, argv);	// Initiate communication with AutoLISP


  for (;;)
    {				/* Request/Result loop */
      if ((stat = ads_link (scode)) < 0)
	      {
	        cout << "Error: %d\n", stat;
          cout.flush();
	        exit (1);
	      }
      scode = RSRSLT;		// Reset result code 


      switch (stat)
	      {
	      case RQXLOAD:		// Load & define functions

	            scode = load () ? -RSRSLT : -RSERR;
              initialize();
	            break;

	      case RQXUNLD:		// Unload functions 

	            scode = unload () ? -RSRSLT : -RSERR;
	            break;

	      case RQSUBR:		// Handle request for external function

	            scode = execute () ? RSRSLT : RSERR;
	            break;
                                                               
	      default:
	            break;
	      }
    }
}

static bool operator == (Control const *x, Control const &y)
{
   return (*x).key == y.key;
}    

void dispatch(ads_callback_packet *cbpkt)
{
   char value[50];
   ads_get_attr_string(cbpkt->tile, "key", value, 50);

   const Control c(value);

   set <Control *, less<Control *> >::iterator i =
   find(Dialog::current->controls.begin(), 
      Dialog::current->controls.end(), Control(value));

   Dialog::current->HandleMsg((*i)->cmdId, cbpkt);
}


Control::Control (const char *key,  int cmdId, 
                     CLIENTFUNC callback)
{
      Control::callback = callback;
      Control::key = key;
      Control::cmdId = cmdId;
}



//////////////////////////////////////////////////////////////////////////

ListBox::ListBox(const ListBox& listbox)
{
 copy(listbox.items.begin(), listbox.items.end(), items.begin() );
}
/**
 **Doda string /data/ na konec seznama za prikaz
 **/
void ListBox::add(const char *data)
{
  items.push_back(Item(data));
}

/**
 ** Zbrise obstoje"ci seznam in pripravi potrebno za novega
 **/
void ListBox::newList()
{
   items.erase(items.begin(), items.end());
}

/**
 ** Zahteva izris seznama v dialog oknu
 **/
void ListBox::paint(ads_hdlg hdlg)
{
  ads_start_list(hdlg, (char *)(const char *)key, LIST_NEW, 0);
  // items.forAll(paintItem, hdlg);

  for_each(items.begin(), items.end(), Item::paint);
  ads_printf("lb paint");
  ads_end_list();
}


/**
 ** Vrne /i/-ti string iz seznama
 **/
const char * ListBox::GetString(int i)
{
  return (const char *) items[i].item;
}
/**
 ** Izrise en string v dialog oknu
 **/
void Item::paint(Item i)
{
   ads_add_list((char *)(const char *)i.item);
}


//////////////////////////////////////////////////////////////////////

/**
 ** Kreira novo polje za vnos z referenco /key/ in "stevilko sporo"cila
 ** /cmdId/. /defaultText/ je mo"zno uporabiti za prednastavljeni tekst,
 ** ki se prika"ze na Dialog oknu.
 **/
EditBox::EditBox(const char *key, int cmdId, const char *defaultText)
  : Control(key, cmdId)
{
  EditBox::defaultText = defaultText;
}

/**
 ** Izrise tekst v EditBox oknu
 **/
void EditBox::paint(ads_hdlg hdlg)
{
  ads_set_tile(hdlg, (char *)(const char *)key, 
                (char *)(const char *)defaultText);
}

/** Nastavi /defaultText/ na tekst /text/ **/
void EditBox::Set(const char *text)
{
  defaultText = text;
}



/////////////////////////////////////////////////////////

Dialog *Dialog::current = NULL;


#if 0

/** {secret} **/
void Dialog::addDialogControl(Control * data, void *hdlg)
{
  ads_action_tile(*(ads_hdlg *)hdlg,
    (char *)(const char *)data->key, data->callback);
}
#endif



/**
 ** Kreira dialog z imenom /filename/ datoteke .dcl z imenom dialoga
 ** /dialogKey/ in podrocjem pomoci /topic/.
 **/
Dialog::Dialog(const char *filename, const char *dialogKey, 
               const char *topic)
{
  previous = current;
  current = this;

  file = filename;
  Dialog::dialogKey = dialogKey;
  if (topic == NULL)
    helpTopic = dialogKey;
  current = this;
}
   


/** {duh} **/
Dialog::~Dialog()
{
  set <Control *, less<Control *> >::iterator i;

  for(i = controls.begin(); i != controls.end(); ++i)
      delete *i ;

  current = previous;
}



/**
 ** Podobno kot pri gumbih s to funkcijo tu prestrezamo sporo"cila
 ** za sezname (ListBox). /cmdId/ je "stevilka seznama, /cbpkt/ pa
 ** stuktura z informacijo o vrstici in na"cinu izbora, kot je to
 ** v normalnih /ADS callback/ funkcijah.
 **/
void Dialog::HandleMsg(int cmdId, ads_callback_packet *cbpkt)
{
#ifdef ADSDEBUG

  ads_printf("ListBox with id: %d was selected with reason %d.\n", 
             cmdId, cbpkt->reason);
#endif

  cmdId = 0;
  cbpkt = NULL;
}

/**
 ** Glavna funkcija za zagon Dialog okna, v kateri je zanka za prestrezanje
 ** in dispe"ciranje sporo"cil.
 **/
void Dialog::Run()
{

  ads_load_dialog((char *)(const char *)file, &dlgId);

  if (dlgId < 0)
    {
      ads_fail("Napaka pri odpiranju dialoga");
      return;
    }

  ads_new_dialog ((char *)(const char *)dialogKey, dlgId, NULLCB, &hdlg);

  if (hdlg == NULL)
    {
      ads_fail ("ads_new_dialog funkcija ni uspela");
      ads_unload_dialog (dlgId);
      return;
    }

  // add dialog controls

  set <Control *, less <Control *> >::iterator i;

  for(i = controls.begin(); i != controls.end(); ++i)
   {
      (*i)->paint(hdlg);
      (*i)->addTile(hdlg);    
   }
  
  StartHook();

  status = DLGSTATUS;
  while (status >= DLGSTATUS)
    {
      ads_start_dialog (hdlg, &status);

      switch (status)
        {
        case DLGOK:
          Ok();
          break;
        case DLGCANCEL:
        case DLGALLDONE:
          Cancel();
          break;
        default:
          HandleMsg();
          break;
        }
     }
//  ads_unload_dialog(dlgId);

  return;
}

#if 0

/**
 ** S to funkcijo lahko registriramo funkcije kot je to normalno v ADS
 ** s /CALLB/ na"cinom. /tileFunc/ je ADSCALLBACK funkcija,
 ** ki se izvr"si ob dogodku /key/ v dialogu.
 **/
void Dialog::Register(CLIENTFUNC tileFunc, const char *key)
{
  Control *c = new Control(tileFunc, key);
  controls.insert(c);
}



/**  {duh} **/
void Dialog::insert(ListBox listbox)
{
  listboxes.push_back(listbox);
}
/** {duh} **/
void Dialog::insert(EditBox editbox)
{
  editboxes.insert(editbox);
}


#endif


/**
 ** Dodajamo ukaze dialogu in s tem omogo"cimo izvr"sitev sporo"cila.
 **/
void Dialog::insert(Control *control)
{
  controls.insert(control);
}



syntax highlighted by Code2HTML, v. 0.9.1