// Scanner gio-file per Photogenics
// usa lo scanner.device
// (del tipo non ottimizzato per gli scanner a tripla passata)

// © 1996 by Andreas Günther
// © 1997 traduzione italiana a cura della Fractal Minds - Roma

#include "pgs_protos.h"
#include "pgs_pragmas.h"
#include "gio.h"
#include "devices/scanner.h"



/* prototypes */
__asm ULONG __saveds GioExamine(register __a0 struct GIOData *giodata);
__asm ULONG __saveds GioRead(register __a0 struct GIOData *giodata);
__asm ULONG __saveds GioWrite(register __a0 struct GIOData *giodata);
/* end of prototypes */

#define PgsBase giodata->PgsBase
#define IntuitionBase giodata->IntuitionBase


char *ver="$VER:Scanner.gio 1.0 (12.01.96) by Andreas Günther";

__asm ULONG __saveds GioInfo(void)
{
  return(GIOF_LOADER24);
}


static ULONG Memory(ULONG width, ULONG height, ULONG scanmode)
{
  return(width*height*3);   // Ogni pixel vuole 3 byte
}

__asm ULONG __saveds GioExamine(register __a0 struct GIOData *giodata)
{
  struct MsgPort *port,*progport; // Port per IO e avanzamento dei  					    
					// report
  struct IOScanRequest *req;

  struct TagItem select_tags[]={
    {SCAN_Screen, NULL},
    {SCAN_NotWithOne, TRUE},
    {TAG_DONE, 0}};

  struct TagItem setparams_tags[]={
    {SCAN_Screen, NULL},
    {SCAN_IncludeModes, NULL},
    {SCAN_MemoryFunc, (ULONG)Memory},
    {TAG_DONE, 0}};

// Modi di scansione supportati (per SCAN_IncludeModes):
  ULONG modes[]={4, SCM_TXT, SCM_HT, SCM_GREY8, SCM_COLOR8};
  
  setparams_tags[0].ti_Data=select_tags[0].ti_Data=(ULONG)giodata->PgsScreen;
  setparams_tags[1].ti_Data=(ULONG)modes;
  giodata->Error = LOAD_OK;

  if(NULL==(port=CreateMsgPort()))
   {
    giodata->Error=LOAD_RAMERR;
    return(giodata->Error);
   }

  if(NULL==(progport=CreateMsgPort()))
   {
    DeleteMsgPort(port);
    giodata->Error=LOAD_RAMERR;
    return(giodata->Error);
   }

  if(NULL==(req=CreateIORequest(port,sizeof(struct IOScanRequest))))
   {
    DeleteMsgPort(progport);
    DeleteMsgPort(port);
    giodata->Error=LOAD_RAMERR;
    return(giodata->Error);
   }

  if(0!=OpenDevice("scanner.device",0,(struct IORequest *)req,0))
   {
    DeleteIORequest(req);
    DeleteMsgPort(progport);
    DeleteMsgPort(port);
    giodata->Error=LOAD_UNAVAILABLE;
    return(giodata->Error);
   }

  giodata->UserData=(ULONG)port;
  giodata->UserData2=(ULONG)progport;
  giodata->UserData3=(ULONG)req;

  req->Req.io_Command=SCCMD_SELECT;  
  req->Tags=select_tags;
  DoIO((struct IORequest *)req);

  if(req->Req.io_Error!=ScanErr_OK)
   {
    CloseDevice((struct IORequest *)req);
    DeleteIORequest(req);
    DeleteMsgPort(progport);
    DeleteMsgPort(port);
    giodata->Error=LOAD_RAMERR;
    return(giodata->Error);
   }

  req->Req.io_Command=SCCMD_SETPARAMS;
  req->Tags=setparams_tags;
  DoIO((struct IORequest *)req);

  if(req->Req.io_Error!=ScanErr_OK)
   {
    CloseDevice((struct IORequest *)req);
    DeleteIORequest(req);
    DeleteMsgPort(progport);
    DeleteMsgPort(port);
    switch(req->Req.io_Error)
     {
      case ScanErr_Cancel:
      case IOERR_ABORTED:   giodata->Error=LOAD_ABORTED;  break;
      case IOERR_OPENFAIL:
      case IOERR_UNITBUSY:  giodata->Error=LOAD_UNAVAILABLE;   break; 
      case ScanErr_NoMemory:giodata->Error=LOAD_RAMERR;    break;
      default:              giodata->Error=LOAD_ABORTED;  break;
     }
    return(giodata->Error);
   }

  giodata->Depth=24;
  giodata->Height=req->AreaHeight;
  giodata->Width=req->AreaWidth;

  giodata->Error = LOAD_OK;

  return(giodata->Error);
}


__asm ULONG __saveds GioRead(register __a0 struct GIOData *giodata)
{
  struct MsgPort *port,*progport; // Port per IO e avanzamento report
  struct IOScanRequest *req;
  struct ProgressMsg *msg;
  BOOL end=FALSE;     // per loop di input
  int line=0;

  struct TagItem read_tags[]={
    {SCAN_OpenWindow, FALSE},
    {SCAN_ProgressMsgPort, NULL},
    {TAG_DONE, 0}};

  struct TagItem abort_tags[]={
    {SCAN_Abort, TRUE},
    {TAG_DONE, 0}};

  port=(struct MsgPort *)giodata->UserData;
  progport=(struct MsgPort *)giodata->UserData2;
  req=(struct IOScanRequest *)giodata->UserData3;

  giodata->Error = LOAD_ABORTED;

  read_tags[1].ti_Data=(ULONG)progport;
  req->Req.io_Command=CMD_READ;
  req->Tags=read_tags;
  req->DataFormat=FORMAT_RGB8;
  req->Req.io_Length=3*req->AreaWidth;

  req->Req.io_Data=GetLine(giodata,line);
  SendIO((struct IORequest *)req);
  SetProgress(NULL,0);      // apre la finestra di progresso

  do
   {
    Wait((1<<port->mp_SigBit) | (1<<progport->mp_SigBit));

    while(NULL!=(msg=(struct ProgressMsg *)GetMsg(progport)))
     {
      if(SetProgress(NULL,msg->Complete)!=1)
       {
        if(!CheckIO((struct IORequest *)req))
          AbortIO((struct IORequest *)req);
        else
          req->Tags=abort_tags;
       }
      ReplyMsg((struct Message *)msg);
     }

    while(NULL!=GetMsg(port))
     {
      ReleaseLine(giodata,line);
      line++;
      switch(req->Req.io_Error)
       {
        case ScanErr_OK:
          req->Req.io_Data=GetLine(giodata,line); 

	//scan prossima linea

          SendIO((struct IORequest *)req);
          break;
        case ScanErr_ScanEnd:
          giodata->Error=LOAD_OK;
          end=TRUE;
          break;
        case IOERR_UNITBUSY:
        case IOERR_OPENFAIL:
        case ScanErr_WrongFormat:
          giodata->Error=LOAD_UNAVAILABLE;
          end=TRUE;
          break;
        case ScanErr_NoMemory:
          giodata->Error=LOAD_RAMERR;
          end=TRUE;
          break;
        case ScanErr_Cancel:
        case IOERR_ABORTED:
        default:
          giodata->Error=LOAD_ABORTED;
          end=TRUE;
          break;
       }
     }
   }
  while(!end);

  CloseProgress();

  CloseDevice((struct IORequest *)req);
  DeleteIORequest(req); 
  DeleteMsgPort(progport);
  DeleteMsgPort(port);

  return(giodata->Error);
}


__asm ULONG __saveds GioWrite(register __a0 struct GIOData *giodata)
{
	giodata->Error=LOAD_WRONGTYPE;
	return(giodata->Error);
}
