#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>

#include <dos/dos.h> /* For FileInfoBlock */


#include <libraries/mui.h>
#include <libraries/asl.h>
#include <inline/muimaster.h>

#include "protocol.h"
#include "hard.h"

#include "mui_tilist.h"


struct UtilityBase    *UtilityBase=NULL;
struct IntuitionBase  *IntuitionBase=NULL;
struct GfxBase        *GfxBase=NULL;
struct Library        *MUIMasterBase=NULL;


Object *App=NULL; /* Application object       */

struct MUI_CustomClass *ti_mcc;


/* Disable auto-library-opening : */
//int __initlibraries=0;


#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))


#define LISTFILES_SELECT      1
#define LISTFILES_DBLCLICK    2
#define LISTFILES_DELETE      3
#define LISTFILES_PARENT      4
#define LISTFILES_PATHCHANGED 5
#define LISTVARS_SELECT       15
#define LISTVARS_GETVAR       21
#define LISTVARS_SENDVAR      23

BOOL open_libs(void );
void close_libs(void );
void clean_up(int sig);

int debug_mode=0; /* used by hard.c */

int main(int argc, char **argv)
{
  BOOL running = TRUE;
  ULONG sig;
  Object * main_window; /* Window object            */
  Object * button_listfolders   ; /* Edit Button object       */
  Object * button_update ; /* Delete Button object     */
  Object * button_recv   ;
  Object * button_send   ;
  Object * button_parent   ;
  Object * list_files   ;
  Object * list_vars   ;
  Object * text_ti89 ;
  Object * pop_asl;
  Object * string_path;


  signal(SIGINT,&clean_up);

  if ( argc > 1 )
    debug_mode = 1;

  if ( ! open_libs() )
  {
    printf("Cannot open libs.\n");
    return(0);
  }

  if ( ti_openport() )
    clean_up(0);

  //printf("Creating Custom Class\n");

  if (!(ti_mcc = MUI_CreateCustomClass(NULL,MUIC_Listview,NULL,sizeof(struct MUITIList_Data),MUITIList_Dispatcher)))
  {
    printf("Cannot create custom class.\n");
    clean_up(0);
  }



  App = ApplicationObject,
    MUIA_Application_Title  , "Sashi89",
		MUIA_Application_Version , "$VER: Sashi89 0.5 (26.01.01)",
    MUIA_Application_Copyright , "©1999/2000, Olivier Croquette",
    MUIA_Application_Author  , "Olivier Croquette",
    MUIA_Application_Description, "Link to TI-89.",
    MUIA_Application_Base  , "None",
    SubWindow, main_window = WindowObject,
      MUIA_Window_ID, MAKE_ID('M','A','I','N'),
      MUIA_Window_Title, "Sashi89",
      WindowContents, VGroup,
        Child, HGroup,
          Child, VGroup,
            Child, TextObject,
              TextFrame,
              MUIA_Background, MUII_TextBack,
              MUIA_Text_Contents, "Computer",
            End,
            Child, list_files = ListviewObject,
              MUIA_Listview_List, DirlistObject,
                InputListFrame,
                MUIA_Dirlist_Directory  , "PROGDIR:",
                /*MUIA_Dirlist_FilterDrawers, TRUE,*/
                /*MUIA_Dirlist_AcceptPattern,"#?",*/
                /*MUIA_List_Format   , "COL=0",*/
                End,
              End,
              Child,ColGroup(2),
                Child, KeyLabel2("Path:",'p'),
                Child, pop_asl = PopaslObject,
                  MUIA_Popstring_String, string_path = KeyString(0,256,'p'),
                  MUIA_Popstring_Button, PopButton(MUII_PopFile),
                          ASLFR_TitleText, "Please select path...",
                          ASLFR_InitialDrawer, "Progdir:",
                          ASLFR_DrawersOnly, TRUE,
                End,
              End,
            Child, button_send   = SimpleButton("_Send" ),
            Child, button_parent = SimpleButton("_Parent" ),
            End,
          Child, VGroup,
            Child, text_ti89=TextObject,
              TextFrame,
              MUIA_Background, MUII_TextBack,
              MUIA_Text_Contents, "TI89",
            End,
            Child, list_vars = (Object *)NewObject(ti_mcc->mcc_Class, NULL,
              MUIA_Listview_List, ListObject,
                ReadListFrame,
                MUIA_Font,                MUIV_Font_Fixed,
                MUIA_Background,          MUII_ListBack,
                MUIA_List_AutoVisible,    TRUE,
              End,
              TAG_DONE),
            Child, button_recv = SimpleButton("_Get" ),
            Child, button_listfolders = SimpleButton("_Folders" ),
            Child, button_update = SimpleButton("_Update"),
            End,
          End,
        End,
      End,
    End;

  if (!App)
  {
    printf("Failed to create Application ( listvars = %p )\n",list_vars);
    clean_up(0);
  }


  DoMethod(main_window,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,App,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit);

  DoMethod(list_files ,MUIM_Notify,MUIA_List_Active,MUIV_EveryTime,App,2,MUIM_Application_ReturnID,LISTFILES_SELECT);
  DoMethod(list_files ,MUIM_Notify,MUIA_Listview_DoubleClick,TRUE,App,2,MUIM_Application_ReturnID,LISTFILES_DBLCLICK);

  DoMethod(string_path,MUIM_Notify,MUIA_String_Contents,MUIV_EveryTime,App,2,MUIM_Application_ReturnID,LISTFILES_PATHCHANGED);

  DoMethod(button_parent ,MUIM_Notify,MUIA_Pressed,FALSE,App,2,MUIM_Application_ReturnID,LISTFILES_PARENT );

  DoMethod(button_recv ,MUIM_Notify,MUIA_Pressed,FALSE,App,2,MUIM_Application_ReturnID,LISTVARS_GETVAR );
  DoMethod(button_send ,MUIM_Notify,MUIA_Pressed,FALSE,App,2,MUIM_Application_ReturnID,LISTVARS_SENDVAR );

  DoMethod(button_update      ,MUIM_Notify,MUIA_Pressed,FALSE,list_vars,1,MUIM_TIList_ListVars);
  DoMethod(button_listfolders ,MUIM_Notify,MUIA_Pressed,FALSE,list_vars,1,MUIM_TIList_ListFolders);

  DoMethod(main_window,MUIM_Window_SetCycleChain,list_files,list_vars,button_listfolders,button_update,button_recv,NULL);

  set(list_files,MUIA_Dirlist_Directory,(ULONG)"PROGDIR:");
  set(list_vars,MUIA_TIList_ParentApp,(ULONG)App);
  set(list_vars,MUIA_TIList_ParentWindow,(ULONG)main_window);

  set(main_window,MUIA_Window_Open,TRUE);

  //set(list_vars,MUIA_TIList_CurrentFolder,"toto");

  while (running)
  {
    ULONG ret = DoMethod(App,MUIM_Application_Input,&sig);

    switch (ret)
    {
      case MUIV_Application_ReturnID_Quit:
      {
        ULONG active;
        get(pop_asl,MUIA_Popasl_Active,&active);
        if (active)
          MUI_Request(App,main_window,0,"Sashi89 error","OK",
                      "Cannot quit now, still some asl popups opened.");
        else
          running = FALSE;
        break;
      }

      case LISTFILES_DBLCLICK:
      {
        char newpath[200], *oldpath; /* Todo: 200 */
        struct FileInfoBlock *fib;

        DoMethod(list_files,MUIM_List_GetEntry,MUIV_List_GetEntry_Active,&fib);

        if ( ! fib || fib->fib_DirEntryType < 0 ) /* if not a valid directory */
          break;

        get(list_files,MUIA_Dirlist_Directory,&oldpath);

        if ( oldpath[0] != '\0' )
          if ( oldpath[strlen(oldpath)-1] != ':' )
            sprintf(newpath,"%s/%s",oldpath,fib->fib_FileName);
          else
            sprintf(newpath,"%s%s",oldpath,fib->fib_FileName);
        else
          strcpy(newpath,fib->fib_FileName);

        set(list_files,MUIA_Dirlist_Directory,(ULONG)newpath);
        break;
      }

      case LISTFILES_PATHCHANGED:
      {
        char *content;
        get(string_path,MUIA_String_Contents,&content);
        set(list_files,MUIA_Dirlist_Directory,(ULONG)content);
        break;
      }

      case LISTFILES_PARENT:
      {
        int i;
        char newpath[200], *oldpath; /* TODO : 200 */

        get(list_files,MUIA_Dirlist_Directory,&oldpath);

        for ( i=strlen(oldpath); i>0 && oldpath[i] != ':' && oldpath[i] != '/' ; i--)
          {}

        strcpy(newpath,oldpath);
        if ( newpath[i] != ':' )
          newpath[i] = '\0';
        else
          newpath[i+1] = '\0';

        set(list_files,MUIA_Dirlist_Directory,(ULONG)newpath);


        break;
      }

      case LISTVARS_GETVAR:
      {
        char *whatisclicked;
        char *current_folder="";

        get(list_vars,MUIA_TIList_CurrentSelectedVar,&whatisclicked );

        if ( whatisclicked[0] == '\0' )
          get(list_vars,MUIA_TIList_CurrentSelectedFolder,&whatisclicked );
        else
          get(list_vars,MUIA_TIList_CurrentFolder, &current_folder);

        if ( whatisclicked )
        {
          if ( whatisclicked[0] != '.' )
          {
            int code;
            char filename[200],*path; /* TODO : 200 */

            get(list_files,MUIA_Dirlist_Directory,&path);

            if ( path[strlen(path)-1] == ':' )
              sprintf(filename,"%s%s.89g",path,whatisclicked);
            else
              sprintf(filename,"%s/%s.89g",path,whatisclicked);

            printf("Getting %s in file %s...",whatisclicked,filename);
            fflush(stdout);

            if ( current_folder[0] ) /* Download var */
              code = ti_getvar(current_folder,whatisclicked,filename);
            else /* Download dir */
              code = ti_getfolder(whatisclicked,filename);
            if ( code )
              printf("error %d\n",code);
            else
              printf("OK\n");
            DoMethod(list_files,MUIM_Dirlist_ReRead);
          }
        }
        else
          printf("Can't get any variable if no TI variable selected !\n");
      }
      break;

      case LISTVARS_SENDVAR:
      {
        char *whatisclicked;

        get(list_files,MUIA_Dirlist_Path,&whatisclicked);
        if ( whatisclicked )
        {
          int code;
          clock_t clock1=clock(); /*temp. */
          struct FileInfoBlock *fib;
          char *current_folder;

          DoMethod(list_files,MUIM_List_GetEntry,MUIV_List_GetEntry_Active,&fib);
          get(list_vars,MUIA_TIList_CurrentFolder, &current_folder);


          printf("Sending %s...",whatisclicked);
          fflush(stdout);
          code = ti_sendfile(whatisclicked,current_folder);
          if ( code )
          {
            printf("error %d\n",code);
            MUI_Request(App,main_window,0,"Sashi error","_OK",
                      ti_code2string(code));
          }
          else
          {
            int time_elaps=(clock()-clock1);
            printf("OK. %ld bytes in %2.2f seconds => %4.0f cps\n",
              (long int)fib->fib_Size,
              ((1.0*time_elaps)/CLK_TCK),
              (CLK_TCK*(1.0*fib->fib_Size)/(time_elaps))
             );

            DoMethod(list_vars,MUIM_TIList_Update);
          }
        }
      }
      break;
    }

    if (running && sig)
      Wait(sig);

    /*if ( ret != 0 )
      printf("fin switch\n");*/
  }

  clean_up(0);

  return(0);
}



BOOL open_libs(void )
{

  if ( !(UtilityBase=(struct UtilityBase *)OpenLibrary((UBYTE *)"utility.library",0)) )
  {
    close_libs();
    return(0);
  }

  if ( !(IntuitionBase=(struct IntuitionBase *) OpenLibrary((UBYTE *)"intuition.library",39)) )
  {
    close_libs();
    return(0);
  }

  if ( !(GfxBase=(struct GfxBase *) OpenLibrary((UBYTE *)"graphics.library",0)) )
  {
    close_libs();
    return(0);
  }

  if ( !(MUIMasterBase=OpenLibrary((UBYTE *)MUIMASTER_NAME,19)) )
  {
    close_libs();
    return(0);
  }

  return(1);
}



void close_libs(void )
{
  //printf("closing libs\n");
  if ( UtilityBase )
    CloseLibrary((struct Library *)UtilityBase);

  if ( IntuitionBase )
    CloseLibrary((struct Library *)IntuitionBase);

  if ( GfxBase )
    CloseLibrary((struct Library *)GfxBase);

  if ( MUIMasterBase )
    CloseLibrary(MUIMasterBase);
  //printf("ok\n");
}


void clean_up(int sig)
{
  sig = sig; /* avoid warning because sig is not used */

  //printf("cleanup\n");

  close_libs();

  //printf("dispose app\n");
  if (App)
    MUI_DisposeObject(App);
  //printf("dispose cc\n");
  if ( ti_mcc )
    MUI_DeleteCustomClass(ti_mcc);

  //printf("close port\n");
  ti_closeport();
  //printf("exit\n");
  exit(0);
}

