/*****************************************************************************
 * 
 * Nom                          : utils.c
 * desc                         : utilitaires projet
 *
 * version                      : $VER: utils.c 2.4 (12.08.99)
 *
 * ver 2.1:   error handling
 * ver 2.2:   some bug fixed
 * ver 2.2ß2: stay in the background now
 * ver 2.2ß3: LoadConf used a uninitialized variable (pointer to WBScreen)
 * ver 2.3ß4: problem when notifyint was not present
 *            draw or not the seconds arrow
 * ver 2.3ß5: redraw when window (de)selected
 *            uses rtracker.library for allocation
 *            18-06-99 Code cleaning
 * ver 2.4  : Uses led.image for displaying time
 *            return version when dialoging with other progs
 *
 *****************************************************************************
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <exec/exec.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/tasks.h>
#include <exec/libraries.h>
#include <dos/datetime.h>
#include <dos/dosextens.h>
#include <workbench/workbench.h>
#include <libraries/notifyintuition.h>
#include <clib/rtracker_protos.h>
#include <pragmas/rtracker_pragmas.h>
#include <intuition/intuition.h>
#include <intuition/imageclass.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/gadtools.h>
#include <proto/icon.h>
#include "utils.h"
#include "timer.h"
#include "tracewin.h"
#include "notify.h"
#include "partial.h"
#include "conf.h"
#include "obp.h"
ULONG top = 0 ;
/* system gadgets
 */
struct Gadget szgdg = {
  NULL,
  0,0, 100, 15,
  GFLG_GADGHNONE,
  GACT_RELVERIFY,
  GTYP_WDRAGGING,
  NULL,
  NULL,
  NULL,
  0,
  NULL,
  10,
  NULL
} ;
struct Gadget tagdg = {
  NULL,
  0,0, 0, 0,
  GFLG_GADGHNONE,
  GACT_RELVERIFY,
  GTYP_SIZING,
  NULL,
  NULL,
  NULL,
  0,
  NULL,
  11,
  NULL
} ;
/* Library base
 */
struct Library * NotifyIntuitionBase ;
struct Library * RTrackerBase ;
#ifdef __VBCC__
struct Library * GfxBase = NULL ;
struct Library * IntuitionBase = NULL ;
struct Library * GadToolsBase = NULL ;
#endif

char * ptrTime = NULL ;
struct DateTime * dt = NULL ;

idWin * init(struct WBArg * appName) {
  /* prototype
   */
  struct ClassLibrary *openclass (STRPTR name, ULONG version) ;
  /* initalize the main window
   * and the project
   */
  struct Screen  * WBScreen ;                 // lock on WB
  idWin * prjWin ;                            // main prj
  

  if ((RTrackerBase = OpenLibrary("rtracker.library",10)) == NULL) {
    /* can't open neede library then quit
     */
    printf("Couldn't load rtracker.library version 1.0\n") ;
    return(NULL) ;  
  }
  /* (rtracker init resource )
   */  
  InitResource() ;
  
  #ifdef __VBCC__
  if ((IntuitionBase = OpenLibrary("intuition.library", 0L)) == NULL) //#?= ...
  {
    puts("We are all doomed...");
    return (NULL) ;
  }

  if ((GfxBase = OpenLibrary("graphics.library", 0L)) == NULL)
  {
    ez_req("Backclock Error", "Couldn't open graphics.library", "Øv...", NULL ) ;
    return(NULL) ;
  }

  if ((GadToolsBase = OpenLibrary("gadtools.library", 0)) == NULL)
  {
    ez_req("Backclock Error", "couldn't open gadtools.library", "Shit!", NULL ) ;
    CloseLibrary(IntuitionBase);
    return(NULL);
  }
  #endif


  if ((prjWin = NewAllocMem(sizeof(idWin), MEMF_PUBLIC|MEMF_CLEAR)) == NULL) { 
    /* get space for the prj
     */
    close(prjWin) ;
    return(NULL) ;
  }
    
  if ((prjWin->date = NewAllocMem(sizeof(struct DateStamp), MEMF_PUBLIC)) == NULL) {
    /* get space for the date
     */
    close(prjWin) ;
    return(NULL) ;
  }
    
  if ((prjWin->Notify = NewAllocMem(sizeof(struct IntNotifyRequest), MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
    /* get space for the notify request
     */
    close(prjWin) ;
    return(NULL) ;
  }
  
  
  if ((NotifyIntuitionBase = NewOpenLibrary(NOTIFYINTUITIONNAME, NOTIFYINTUITION_VMIN)) != NULL) {
        /* open the window
         */
    
    WBScreen = LockPubScreen("Workbench") ;
    top = WBScreen->BarHeight ; 
    prjWin->wb   = WBScreen ;
    /* initialize the leds
     */
    prjWin->imlib = openclass("images/led.image", 37) ;
    if (prjWin->imlib) {
      /* get a newobject from the led library
       * nb: if led can't be opened then do nothing
       */
      prjWin->im = NewObject(NULL, "led.image", IA_FGPen, 1,
                                        IA_BGPEN, 0,
                                        TAG_DONE) ;
    }
    LoadConf(prjWin) ;                /* load saved preferences (env:backclock.prefs) */
    init_bitmap(prjWin) ;             /* initialize the bitmap */
    prjWin->win = OpenWindowTags(NULL, WA_Left,   prjWin->backWin.posX,
                                       WA_Top,         prjWin->backWin.posY,
                                       WA_Width,       prjWin->backWin.width,
                                       WA_Height,      prjWin->backWin.height,
                                       WA_IDCMP,       IDCMP,
                                       WA_MinWidth,      50,
                                       WA_MinHeight,   50,
                                       WA_MaxHeight,   MAXH,
                                       WA_MaxWidth,    MAXH,
                                       WA_Flags,       WFLG,
                                       WA_ScreenTitle, TXT_SCRTITLE,
                                       WA_NewLookMenus, TRUE,
                                       WA_PubScreenName, "Workbench", TAG_DONE) ;
    
    szgdg.Height = top - 1 ;
    szgdg.NextGadget = &tagdg ;
    tagdg.LeftEdge  = prjWin->win->Width /2 ;
    tagdg.TopEdge   = prjWin->win->Height - 20 ;
    tagdg.Width     = prjWin->win->Width /2 ;
    tagdg.Height    = 20 ;
  
    AddGList(prjWin->win, &szgdg, 0, 2, NULL) ;
   
    RefreshGList(&szgdg, prjWin->win, NULL, -1) ;
                                                                                             
    if (prjWin->win == NULL)
      /* the window did not open so quit
       */
      return(NULL) ;
   
    if (prjWin->wb)
      UnlockPubScreen(NULL, WBScreen) ;
    
                                                                                                
  }else {
    ez_req("Backclock Error", "Couldn't open notifyintuition.library V2", "Quit", NULL ) ;
    if (prjWin->Notify) NewFreeVec(prjWin->Notify) ;
    prjWin->Notify = NULL ;
    close(prjWin) ;
    return(NULL) ;
  }
  
  if (!initTimer(prjWin))   { close(prjWin) ; return(NULL) ;} /* start timer.device */
  if (!startNotify(prjWin)) { close(prjWin) ; return(NULL) ;} /* start notify */
  if ((ptrTime = NewAllocVec(LEN_DATSTRING, MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {close(prjWin) ; return(NULL) ;}
  if ((dt =      NewAllocVec(sizeof(struct DateTime),  MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {close(prjWin) ; return(NULL) ;}
  getDate(prjWin) ;
  initwin(prjWin) ;                                           /* trace window */
  return prjWin ;
}

void close(idWin * prj) {
  /* free all memory allocations
   */
  int i;
  if (prj) {                                   // struct prj exists (<>0) 
    endNotify(prj) ;
    if (prj->win) CloseWindow(prj->win) ;      // close the window
      free_twin(prj) ; 
    if (prj->date) NewFreeVec(prj->date) ;     // free datestamp
    if (prj->Notify) NewFreeVec(prj->Notify) ; // free struct IntNotify
    closeTimer(prj) ;
    
    if (NotifyIntuitionBase) NewCloseLibrary(NotifyIntuitionBase) ;
    /* free pens
     */
    prj->wb = LockPubScreen("Workbench") ;
    for(i = 0; i<NUM_COLORS; i++)
      freePen(prj, prj->backWin.cmap[i].reg) ;
    if (prj->wb) UnlockPubScreen(NULL, prj->wb) ;
    if (ptrTime) NewFreeVec(ptrTime) ;
    free_bitmap(prj) ;
    NewFreeVec(prj) ;                        // Free the memory
    NewFreeVec(dt) ;
    /* free the led image library
     */
    if (prj->im)    DisposeObject(prj->im) ;
    if (prj->imlib) NewCloseLibrary((struct Library *)prj->imlib) ;
  }
  #ifdef __VBCC__
  if (GadToolsBase)   CloseLibrary(GadToolsBase);
  if (GfxBase)        CloseLibrary(GfxBase);
  if (IntuitionBase)  CloseLibrary(IntuitionBase);
  #endif
  if (RTrackerBase) {
    /* use rtracker.library to free forgotten allocation
     */
    CloseResource() ;
    CloseLibrary(RTrackerBase) ;
  }
}
void getDate(idWin * prj) {
  /* fill prj with the date
   */ 
  DateStamp(prj->date) ;
  if (ptrTime) {  
    CopyMem(prj->date, &(dt->dat_Stamp), sizeof(struct DateStamp)) ;
    dt->dat_Format = FORMAT_DOS ;
    dt->dat_StrTime = ptrTime ;
    DateToStr(dt) ;
    DateToByte(ptrTime, prj) ;
  }
}

void processwin(idWin* prj) {
  /* process window on received events
   */
  /* variables
   */
  ULONG signals ,                                 /* mask of waiting signals */
        mask,
        class,                                    /* masque of recived signals */
        sigtimer ;
        
  BOOL  stop    = FALSE ;                         /* true if ctrl-c received */
  struct IntuiMessage * msg ;                     /* ptr on intuition message */
  struct MsgPort      * extPort ;
  struct backMsg      * extmsg ;
  
  /* create the public message port
   */
  extPort = NewCreateMsgPort() ;
  extPort->mp_Node.ln_Name = NewAllocVec(10, MEMF_PUBLIC) ;
  CopyMem("backclock", extPort->mp_Node.ln_Name, 10) ;
  AddPort(extPort) ;                              /* add it to the system */
  
  sigtimer =  (1<<(prj->treq->tr_node.io_Message.mn_ReplyPort->mp_SigBit)) ; 
  /* wait signals
   */
  signals = SIGBREAKF_CTRL_C | 
            (1<<(prj->notifyPort->mp_SigBit)) | 
            (1<<(prj->win->UserPort->mp_SigBit)) | sigtimer|
            (1<<(extPort->mp_SigBit)) ;
  
  runtimer(prj,1) ;                               /* start the timer */
  getDate(prj) ;
  effacer(prj) ;                                  /* clean the window */
  retracer(prj) ;                                 /* then redraw it */
  while(!stop) {
    mask = Wait(signals) ;
    if (mask & SIGBREAKF_CTRL_C) {
      /* get signal CTRL C
       */
      stop=TRUE;
    }
    if (mask & (1<<(extPort->mp_SigBit))) {
      /* received message from external prog 
       */
      extmsg = (struct backMsg *)GetMsg(extPort) ;
      switch(extmsg->Class) {
        case BC_Quit:        // received stop
          stop=TRUE ;
          extmsg->error = OK ;
          break;
      
        case BC_GetPrj:      // received send prj
          extmsg->Class |= VERSION<<16 ; // send the version number
          extmsg->ptrPrj = prj ;
          extmsg->error = OK ;
          break;
      
        case BC_RefreshColors:
          setColors(prj) ;
          break;
      
        case BC_Refresh:     // refresh window (redraw)
          reinit_win(prj) ;
          getDate(prj) ;
          effacer(prj) ;
          retracer(prj) ;
          extmsg->error = OK ;
          break;
      
        case BC_SaveConf:
          SaveEnv(prj, TRUE) ;
          if (prj->lastError) extmsg->error = prj->lastError ;
          break;
      
        case BC_UseConf:
          SaveEnv(prj, FALSE) ;
          if (prj->lastError) extmsg->error = prj->lastError ;
          break;
      
        case BC_SetWindow:
          getDate(prj) ;
          setWindow(prj) ;
          
          AbortIO((struct IORequest*)prj->treq) ;
          WaitIO((struct IORequest*)prj->treq) ;
          if(prj->backWin.drawsec) {
            
            runtimer(prj, 1) ;
          }
          extmsg->error = OK ;
          break;
        default:
          break;
      }
      if (extmsg) ReplyMsg((struct Message*)extmsg) ;
    }
    if (mask & (1<<(prj->notifyPort->mp_SigBit))) {
      /* WB closing
       */
      if (partialClose(prj)) partialOpen(prj) ;
    }
    if (mask & 1<<(prj->win->UserPort->mp_SigBit)) {
      /* received intuition message
       */
      while((msg = GT_GetIMsg(prj->win->UserPort)) != NULL) {
        /* reply the message
         */
        class = msg->Class ;
        ReplyMsg((struct Message*)msg) ;
        if(class == IDCMP_CHANGEWINDOW || class == IDCMP_MOUSEBUTTONS) {
          /* set gadgets to the new window
           */

          RemoveGList(prj->win, &szgdg, 2) ;
          szgdg.Width = prj->win->Width ;
          tagdg.LeftEdge = prj->win->Width/2 ;
          tagdg.TopEdge  = prj->win->Height -20 ;
          tagdg.Width    = prj->win->Width /2 ;

          prj->backWin.width = prj->win->Width ;
          prj->backWin.height = prj->win->Height ;      
          prj->backWin.posX = prj->win->LeftEdge ;
          prj->backWin.posY = prj->win->TopEdge ;

          setWindow(prj) ;
          AddGList(prj->win, &szgdg, 0, 2, NULL) ;
          RefreshGList(&szgdg, prj->win, NULL, -1) ;

          SaveEnv(prj, TRUE) ;
        }
      }          
    }
    if (CheckIO((struct IORequest*)prj->treq)) {
      /* message from the timer
       */
      WaitIO((struct IORequest*)prj->treq) ;
      AbortIO((struct IORequest*)prj->treq) ;
      WaitIO((struct IORequest*)prj->treq) ;
      getDate(prj) ;
      if(prj->backWin.drawsec)
        runtimer(prj, 1) ;
      else
        runtimer(prj, 60-(long)(prj->sec)) ;
      effacer(prj) ;
      retracer(prj) ;
    }  
 
  }
  /* clean all when quiting
   */
  AbortIO((struct IORequest*)prj->treq) ;
  WaitIO((struct IORequest*)prj->treq) ;
  RemPort(extPort) ;
  NewFreeVec(extPort->mp_Node.ln_Name) ;
  NewDeleteMsgPort(extPort) ;
     
}

void ez_req(UBYTE * title, UBYTE * body, UBYTE * gadg, APTR arglist ) {
  /* simple function to display EZ_Requester
   */
  struct EasyStruct * ez_rq ;
  
  if (ez_rq = NewAllocVec(sizeof(struct EasyStruct), MEMF_PUBLIC)) {
    if (ez_rq->es_Title = NewAllocVec(strlen(title)+1, MEMF_PUBLIC)) {
     strcpy(ez_rq->es_Title, title) ;
     if (ez_rq->es_TextFormat = NewAllocVec(strlen(body)+1, MEMF_PUBLIC)) {
      strcpy(ez_rq->es_TextFormat, body) ;
      if (ez_rq->es_GadgetFormat = NewAllocVec(strlen(gadg)+1, MEMF_PUBLIC)) {
       strcpy(ez_rq->es_GadgetFormat, gadg) ;
       ez_rq->es_StructSize = sizeof(struct EasyStruct) ;
       ez_rq->es_Flags = 0 ;
       EasyRequestArgs(NULL, ez_rq, NULL, arglist) ;
       NewFreeVec(ez_rq->es_GadgetFormat) ;
      }
      NewFreeVec(ez_rq->es_TextFormat) ;
     }
     NewFreeVec(ez_rq->es_Title) ;
    }
    NewFreeVec(ez_rq) ;
  }
}
/* Try opening the class library from a number of common places */
struct ClassLibrary *openclass (STRPTR name, ULONG version) {
  struct Library *retval;
  UBYTE buffer[256];

  if ((retval = NewOpenLibrary (name, version)) == NULL) {
    sprintf (buffer, ":classes/%s", name);
    if ((retval = NewOpenLibrary (buffer, version)) == NULL) {
      sprintf (buffer, "classes/%s", name);
      retval = NewOpenLibrary (buffer, version);
    }
  }
  return (struct ClassLibrary *) retval;
}

