/* apccomm_am_main.c
   Part of "APCComm" 
   Copyright (C) 2000,2001 Ralf Hoffmann
   Contact: ralf.hoffmann@epost.de

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  
*/
/* $Id: apccomm_am_main.c,v 1.11 2002/06/12 21:01:50 ralf Exp $ */

#include "apccomm_am.h"
#include "apccomm_am_tr.h"
#include "apccomm_all.h"
#include "apccomm_am_main.h"

#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <proto/wb.h>
#include <exec/types.h>
#include <exec/libraries.h>

#ifdef GUI

#include "apccomm_gui.h"
#include "lvhandling.h"

#ifdef _DCC
/* dcc has strcasecmp but no prototype, but stricmp does the same
   and is decleared even the docs so I will use it for dcc
*/
#define strcasecmp stricmp
#endif

struct ReqToolsBase *ReqToolsBase = NULL;

int selected_lvc = -1;
#endif

enum guimodes mode = GUIMODE_RUN;
short StartFromWB = 0;
BOOL freePubScreenName = FALSE;

#ifdef GUI

char *my_getcwd( void )
{
  int cwdsize;
  char *cwd;

  cwdsize = 1024;
  cwd = (char*) malloc( cwdsize );
  if ( cwd != NULL ) {
    while ( getcwd( cwd, cwdsize ) == NULL ) {
      if ( errno == ERANGE ) {
        free( cwd );
        cwdsize *= 2;
        cwd = (char*)malloc( cwdsize );
        if ( cwd == NULL ) break;
      } else {
        free( cwd );
        cwd = NULL;
        break;
      }
    }
  }
  return cwd;
}

void setRSG( const char *text )
{
  struct Gadget *sg;

  if ( text == NULL ) return;
  sg = MainWindowGadgets[ GD_rdsg ];

  GT_SetGadgetAttrs( sg, MainWindowWnd, NULL, GTST_String, text, TAG_END, 0 );
}

void requestReceiveDir( void )
{
  struct rtFileRequester *filereq;
  char filename[109];
  struct Gadget *sg;

  sg = MainWindowGadgets[ GD_rdsg ];

  strcpy( filename, "" );
  if ( filereq = rtAllocRequestA( RT_FILEREQ, NULL ) ) {
    rtChangeReqAttr( filereq, RTFI_Dir, GetString( sg ), TAG_END );
    if ( rtFileRequest( filereq, filename, "Pick a directory", RTFI_Flags, FREQF_NOFILES, RT_PubScrName, (ULONG)PubScreenName, TAG_END ) ) {
      setRSG( filereq->Dir );
    }
    rtFreeRequest( filereq );
  } else {
    rtEZRequest( "Out of memory!", "Oh boy!", NULL, (struct TagItem *)rttags );
  }
}

void initRSG( void )
{
  char *cwd;
  
  cwd = my_getcwd();
  setRSG( cwd );
  if ( cwd != NULL ) free( cwd );
}

void requestAndAddFiles( void )
{
  struct rtFileRequester *filereq;
  struct rtFileList *flist, *tempflist;
  char filename[109];
  char *tstr, *dir;
  struct Gadget *lv;

  lv = MainWindowGadgets[ GD_sflv ];
  if ( filereq = rtAllocRequestA( RT_FILEREQ, NULL ) ) {
    filename[0] = 0;

    flist = rtFileRequest( filereq, filename, "Pick some files", RTFI_Flags, FREQF_MULTISELECT | FREQF_SELECTDIRS, RT_PubScrName, (ULONG)PubScreenName, TAG_END );
    if ( flist ) {
      if ( strlen( filereq->Dir ) < 1 ) {
        dir = my_getcwd();
      } else {
        dir = strdup( filereq->Dir );
      }
      
      tempflist = flist;
      while ( tempflist ) {
        tstr = (char*)malloc( strlen( dir ) + 1 + strlen( tempflist->Name ) + 1 );
        if ( dir[ strlen( dir ) - 1 ] == ':' ) {
          sprintf( tstr, "%s%s", dir, tempflist->Name );
        } else {
          sprintf( tstr, "%s/%s", dir, tempflist->Name );
        }
        addLVC( tstr );
        updateLV( lv, MainWindowWnd );
        free( tstr );
        tempflist = tempflist->Next;
      }
      rtFreeFileList( flist );
    }

    rtFreeRequest( filereq );
  } else {
    rtEZRequest( "Out of memory!", "Oh boy!", NULL, (struct TagItem *)rttags );
  }
}

void removeSelectedEntry( void )
{
  struct Gadget *lv;
  int s;

  if ( selected_lvc < 0 ) return;
  if ( lvcs == NULL ) return;

  lv = MainWindowGadgets[ GD_sflv ];

  removeLVCAtPos( selected_lvc );
  updateLV( lv, MainWindowWnd );
  s = getLVCSize();
  if ( selected_lvc >= s ) {
    selected_lvc = s - 1;
  }
  GT_SetGadgetAttrs( lv, MainWindowWnd, NULL, GTLV_Selected, selected_lvc, TAG_END );
}

void applySLVSG( void )
{
  struct Gadget *sg;
  struct Gadget *lv;
  char *tstr;

  sg = MainWindowGadgets[ GD_slvsg ];
  lv = MainWindowGadgets[ GD_sflv ];

  if ( selected_lvc < 0 ) {
    /* nothing selected so add SG content */
    tstr = GetString( sg );
    if ( strlen( tstr ) > 0 ) {
      addLVC( tstr );
      updateLV( lv, MainWindowWnd );
    }
  } else {
    /* change value at selected position */
    tstr = GetString( sg );
    if ( strlen( tstr ) > 0 ) {
      changeLVC( selected_lvc, tstr );
      updateLV( lv, MainWindowWnd );
    }
  }
}

void CleanUpHandler( void )
{
  if ( ReqToolsBase != NULL )
    CloseLibrary( (struct Library *)ReqToolsBase );
  if ( ( freePubScreenName == TRUE ) && ( PubScreenName != NULL ) )
    free( PubScreenName );
}

#endif

void initParPort( void )
{
  *ddrb=0xff;
  *ddra=0x00;
}

#define os20str_alert "\0\330\17This program needs OS 2.0!\0\1\0\350\37Press any mousebutton\0\0" AMIGA_VERSION_STR

int main(int argc,char **argv)
{
  int s1;
  int o1,o2,o3;
  short *realargs = NULL;

#ifdef GUI
  atexit( CleanUpHandler );
  if ( SysBase->LibNode.lib_Version < 36 ) {
    DisplayAlert( RECOVERY_ALERT, os20str_alert, 45 );
    exit( 1 );
  }
#endif

  int sendargs=argc-1;      /* Wenn es mal Argumente gibt, die nicht das
                               das Ende des Programmes verursachen... */
#ifdef GUI
  struct Gadget *lv;
  struct Node *node;

  if ( ! ( ReqToolsBase = ( struct ReqToolsBase *)OpenLibrary( REQTOOLSNAME, REQTOOLSVERSION ) ) ) {
    struct EasyStruct es = { sizeof( struct EasyStruct ),
                             0,
                             "APCComm Error",
                             "You need reqtools.library V%ld or higher!\nPlease install it in libs:",
                             "Okay" };
    EasyRequest( NULL, &es, NULL, (long)REQTOOLSVERSION );
    exit( 0 );
  }
#endif

  realargs=(short*)malloc(sizeof(short)*argc);
  for(s1=0;s1<argc;s1++) {
    realargs[s1]=1;
  }
  if(argc>1) {
    for(s1=1;s1<argc;s1++) {
      if((strncmp(argv[s1],"-h",2)==0)||(strncmp(argv[s1],"--help",6)==0)) {
#ifdef GUI
        printf("\nAPCComm GUI Version by Ralf Hoffmann\n");
#else
        printf("\nAPCComm by Ralf Hoffmann\n");
#endif
        printf("  Usage: %s [Option]... [<filename>]...\n  Transfer given files to the PC\n\n",argv[0]);
        printf("   -h, --help\t\t\tShow this help\n");
        printf("   -v, --version\t\tShow program-version\n");
        printf("   -V, --verbose\t\tverbose output\n");
        printf("   -q, --quiet\t\t\tno output (except errors)\n");
        printf("   -i\t\t\t\tignore file protection for receiving\n");
#ifdef GUI
        printf("   -s, --send\t\t\timmediately start sending\n");
        printf("   -r, --receive\t\timmediately start receiving\n");
        printf("   --pubscreen PUBSCREENNAME\tUse given pubscreen for gui\n");
#endif
#ifdef GUI
        printf("  When starting without args, APCComm will open a window which will let\n  you choose the files to send or where to receive files.\n");
#else
        printf("  When starting without args, APCComm will receive files from the PC\n");
#endif
        exit(0);
      } else if((strncmp(argv[s1],"-v",2)==0)||(strncmp(argv[s1],"--version",6)==0)) {
        printf("\nAPCComm by Ralf Hoffmann\n  Version %d.%d.%d\n",MAJOR,MINOR,PATCH);
        printf("\n  Program for transfering files between Amiga and PC\n");
#ifdef GUI
        printf("  GUI Version\n");
#endif
        printf("  Contact: ralf.hoffmann@epost.de\n");
        exit(0);
      } else if( ( strncmp(argv[s1],"--verbose",strlen("--verbose"))==0 ) ||
		 ( strncmp(argv[s1],"-V",strlen("-V"))==0 ) ) {
	verbose = 1;
	sendargs--;
	realargs[s1]=0;
      } else if( ( strncmp(argv[s1],"--quiet",strlen("--quiet"))==0 ) ||
		 ( strncmp(argv[s1],"-q",strlen("-q"))==0 ) ) {
	verbose = -1;
	sendargs--;
	realargs[s1]=0;
      } else if( strncmp(argv[s1],"-i",strlen("-i"))==0 ) {
	ignore_prot = 1;
	sendargs--;
	realargs[s1]=0;
#ifdef GUI
      } else if ( ( strncmp( argv[s1], "--send", strlen( "--send" ) ) == 0 ) ||
		  ( strncmp( argv[s1], "-s", strlen( "-s" ) ) == 0 ) ) {
        mode = GUIMODE_SEND;
	sendargs--;
	realargs[s1]=0;
      } else if ( ( strncmp( argv[s1], "--receive", strlen( "--receive" ) ) == 0 ) ||
		  ( strncmp( argv[s1], "-r", strlen( "-r" ) ) == 0 ) ) {
        mode = GUIMODE_RECEIVE;
	sendargs--;
	realargs[s1]=0;
      } else if ( strncmp( argv[s1], "--pubscreen", strlen( "--pubscreen" ) ) == 0 ) {
	sendargs--;
	realargs[s1]=0;
        if ( strncmp( argv[s1], "--pubscreen=", strlen( "--pubscreen=" ) ) == 0) {
          PubScreenName = argv[s1] + strlen( "--pubscreen=" );
        } else {
          if ( ( s1 + 1 ) < argc ) {
            s1++;
            PubScreenName = argv[s1];
	    sendargs--;
            realargs[s1]=0;
          } else {
            fprintf( stderr, "Pubscreen argument missing!\n" );
            exit( 1 );
          }
        }
#endif
      }
    }
  }

  if(init_transferblocks()!=0) {
    fprintf(stderr,"Not enough mem in main()!\nExiting\n");
    exit(1);
  }

#ifdef GUI
  /* Try to setup screen, first the given pubscreen and if this fails, the
     default pubscreen (in most cases Workbench) */
  while ( SetupScreen() != 0 ) {
    if ( PubScreenName != NULL ) {
      rtEZRequest( "Couldn't use pubscreen %s!\nTrying default pubscreen..", "Okay", NULL, (struct TagItem *)rttags, PubScreenName );
      if ( freePubScreenName == TRUE ) free( PubScreenName );
      freePubScreenName = FALSE;
      PubScreenName = NULL;
    } else {
      rtEZRequest( "Couldn't use default pubscreen!", "Okay", NULL, (struct TagItem *)rttags );
      mode = GUIMODE_QUIT;
      break;
    }
  }
  
  rttags[1] = (ULONG)PubScreenName;

  initLVCList();
  for ( s1 = 1; s1 < argc; s1++ ) {
    if ( realargs[s1] == 1 ) {
      addLVC( argv[s1] );
    }
  }
  if ( mode == GUIMODE_RUN ) {
    OpenMainWindowWindow();
    lv = MainWindowGadgets[ GD_sflv ];
    
    updateLV( lv, MainWindowWnd );
    initRSG();
    GT_SetGadgetAttrs( MainWindowGadgets[ GD_ipcb ], MainWindowWnd, NULL, GTCB_Checked, ignore_prot, TAG_END, 0 );
    while ( mode == GUIMODE_RUN ) {
      WaitPort( MainWindowWnd->UserPort );
      HandleMainWindowIDCMP();
    }
    basedir = (char*)malloc( strlen( GetString( MainWindowGadgets[ GD_rdsg ] ) ) + 1 + 1 );
    strcpy( basedir, GetString( MainWindowGadgets[ GD_rdsg ] ) );
    s1 = strlen( basedir );
    if ( s1 > 0 ) {
      if ( ( basedir[ s1 - 1 ] != ':' ) &&
           ( basedir[ s1 - 1 ] != '/' ) ) {
        basedir[ s1 ] = '/';
        basedir[ s1 + 1 ] = '\0';
      }
    }
    CloseMainWindowWindow();
  }
#else
  if ( sendargs > 0 ) {
    mode = GUIMODE_SEND;
    for ( s1 = 1; s1 < argc; s1++ ) {
      if ( realargs[ s1 ] == 1 ) {
        addSendListElem( argv[s1] );
      }
    }
  } else
    mode = GUIMODE_RECEIVE;
#endif

  if ( mode == GUIMODE_QUIT ) {

#ifdef GUI
    deleteLVCList();
#endif

  } else {

#ifdef GUI
    sendargs = 0;
    node = GetHead( lvcs );
    while ( node != NULL ) {
      addSendListElem( node->ln_Name );
      sendargs++;
      node = GetSucc( node );
    }
    deleteLVCList();
#endif
    
    if ( ( mode == GUIMODE_SEND ) && ( SendListIsEmpty() == 1 ) ) {

#ifdef GUI
      rtEZRequest( "Nothing to send!", "Okay", NULL, (struct TagItem *)rttags );
#else
      printf( "Nothing to send!\n" );
#endif

    } else {

      /* Parallelport initieren */
      initParPort();

#ifdef GUI
      OpenConnectWindowWindow();
#else
      if ( ! BE_QUIET ) printf("Waiting for PC:");
      fflush(stdout);
#endif

      synchro();

#ifdef GUI
      CloseConnectWindowWindow();
#else
      if ( ! BE_QUIET ) printf("\nConnection established\n");
#endif
      if ( connect_cancel == 0 ) {

        /* Prepare the outblock */
        putint(outblock,MAJOR);
        putint(outblock+4,MINOR);
        putint(outblock+8,PATCH);
        if ( mode == GUIMODE_SEND ) putint( outblock + 12, 1 );
        else putint(outblock+12,0);

        /* Inform the other side */
        transferblock();
  
        /* Now check the other version */
        o1=getint(inblock);
        o2=getint(inblock+4);
        o3=getint(inblock+8);
        if( (o1!=MAJOR) || (o2!=MINOR) || (o3!=PATCH) ) {
#ifdef GUI
          rtEZRequest( "Wrong version at the other side!\n"
                       "  Expected %ld.%ld.%ld, got %ld.%ld.%ld", "Okay", NULL, (struct TagItem *)rttags, MAJOR, MINOR, PATCH, o1, o2, o3 );
#else
          printf("Wrong version at the other side!\n");
          printf("  Expected %d.%d.%d ,  got %d.%d.%d\n",MAJOR,MINOR,PATCH,o1,o2,o3);
#endif
        } else {
  
          /* Version ok, sending conflict ? */
          o1=getint(inblock+12);
          if( (o1==1) && ( mode == GUIMODE_SEND ) ) {
#ifdef GUI
            rtEZRequest( "Both sides want to send!\n"
                         "  This is not supported!", "Okay", NULL, (struct TagItem *)rttags );
#else
            printf("Both sides want to send!\n");
            printf("  This is not supported!\n");
#endif
          } else {

            if( (o1==0) && ( mode != GUIMODE_SEND ) ) {
#ifdef GUI
              rtEZRequest( "Nothing to do!", "Okay", NULL, (struct TagItem *)rttags );
#else
              printf("Nothing to do!\n");
#endif
            } else {
  
              if ( mode == GUIMODE_SEND ) {
                send();
              } else {
                receive();
              }
            } /* ! if( (o1==0) && (sendargs==0) ) */
          } /* ! if( (o1==1) && (sendargs>0) ) */
        } /* ! if( (o1!=MAJOR) || (o2!=MINOR) || (o3!=PATCH) ) */
      } /* if ( connect_cancel == 0 ) */
    } /* ! if ( ( mode == GUIMODE_SEND ) && ( SendListIsEmpty() == 1 ) ) */
  } /* if ( mode == GUIMODE_QUIT ) */

  freeSendList();
#ifdef GUI
  CloseDownScreen();
#endif

  if ( basedir != NULL ) free( basedir );
  if ( inblock != NULL ) free( inblock );
  if ( outblock != NULL ) free( outblock );
  if ( realargs != NULL ) free( realargs );
  return 0;
}

#ifdef GUI
int wbmain( struct WBStartup *wbs )
{
  struct DiskObject *dob;
  BPTR oldlock;
  char *tstr;
  int i;
  
  if ( SysBase->LibNode.lib_Version < 36 ) {
    /* I think there is no easy way to show this message
       when started from WB */
    DisplayAlert( RECOVERY_ALERT, os20str_alert, 45 );
    exit( 1 );
  }

  if ( wbs->sm_NumArgs > 0 ) {
    oldlock = CurrentDir( (BPTR)wbs->sm_ArgList[0].wa_Lock );
    dob = GetDiskObject( wbs->sm_ArgList[0].wa_Name );
    if ( dob != NULL ) {
      if ( dob->do_ToolTypes != NULL ) {
        if ( ( tstr = FindToolType( dob->do_ToolTypes, "PUBSCREEN" ) ) != NULL ) {
#ifdef GUI
          PubScreenName = strdup( tstr );
          freePubScreenName = TRUE;
#endif
        }
        if ( ( tstr = FindToolType( dob->do_ToolTypes, "VERBOSE_LEVEL" ) ) != NULL ) {
          i = atoi( tstr );
          if ( i == 0 ) verbose = -1;
          else if ( i == 2 ) verbose = 1;
          else verbose = 0;
        }
        if ( ( tstr = FindToolType( dob->do_ToolTypes, "IGNORE_PROT" ) ) != NULL ) {
          if ( ( strcasecmp( tstr, "true" ) == 0 ) ||
               ( strcasecmp( tstr, "yes" ) == 0 ) ||
               ( strcasecmp( tstr, "on" ) == 0 ) ||
               ( strcasecmp( tstr, "1" ) == 0 ) ) {
            ignore_prot = 1;
          } else ignore_prot = 0;
        }
      }
      FreeDiskObject( dob );
    }
    CurrentDir( oldlock );
  }
  StartFromWB = 1;
  return main( 1, NULL );  /* now call normal */
}
#endif
