#include <exec/types.h>
#include <graphics/gfx.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/icon.h>
#include <proto/iffparse.h>
#include <proto/datatypes.h>
#include <proto/layers.h>
#include <prefs/wbpattern.h>
#include <prefs/prefhdr.h>
#include <graphics/gfxmacros.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <exec/memory.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>

#include "ProgressWindow.h"
#include "WBStartup+.h"

#define winwidth 400
#define winheight 80
#define BARHEIGHT 12
#define XOFFSET 75

static UWORD BackgroundPen, HighlightTextPen, ShinePen, ShadowPen;
ULONG __chip Crosshatch = 0x5555AAAA;
static struct WBStartup *wbarg=NULL;


struct ProgressWindowData *CreateProgressWindow(struct WBStartupPrefs *prefs);
void CloseProgressWindow(struct ProgressWindowData *data);
void UpdateProgressBar(struct Window *win, int current, int total);
void ShowIconImage(struct ProgressWindowData *data, struct Image *image);
BOOL LoadBitmap(struct WBStartupPrefs *prefs, struct ProgressWindowData *data, struct Screen *scr);
BOOL InteractiveRunProgram(struct Window *win);
void DisplayProgramName(struct ProgressWindowData *data, char *name, BOOL query);


struct ProgressWindowData *CreateProgressWindow(struct WBStartupPrefs *prefs)
{
  ULONG scrwidth=640,scrheight=200;
  struct Rectangle rect;
  LONG screen_modeID;
  void *vi;
  char buffer[7],*TitleText="Amiga Workbench \0\0\0\0\0\0\0";
  struct IntuiText iText = { 2,0,0,0,0,NULL,NULL,NULL};
  struct DrawInfo *dri;
  struct Screen *scr;

  struct DiskObject *diskobj=NULL;  /* This must be initialized to NULL */
  struct Process *process;
  char buf[200];
  struct Image *image;
  struct ProgressWindowData *windata;
  BOOL success=FALSE;

  if (windata = AllocVec(sizeof(struct ProgressWindowData),MEMF_PUBLIC))
  {
    windata->bitmap=NULL;
    windata->iconundobitmap=NULL;
    windata->filenameundobitmap=NULL;

    if (scr=LockPubScreen(prefs->PubScreenName))
    {
      if (prefs->BackgroundType!=NONE)
        LoadBitmap(prefs,windata,scr);

      /********************************************/
      /* Determine the Size of the visible screen */
      /********************************************/
      screen_modeID = GetVPModeID(&(scr->ViewPort));
      if (screen_modeID != INVALID_ID)
      {
        if (QueryOverscan(screen_modeID, &rect, OSCAN_TEXT))
        {
          scrwidth  = rect.MaxX - rect.MinX + 1;
          scrheight = rect.MaxY - rect.MinY + 1;

          scrwidth  = min(scrwidth,scr->Width);
          scrheight = min(scrheight,scr->Height);
        }
      }

      /*******************************/
      /* Get WBStartup+'s Icon image */
      /*******************************/
      if (process = (struct Process *)FindTask(NULL))
      {
        NameFromLock(process->pr_HomeDir,buf,199);
        AddPart(buf,process->pr_Task.tc_Node.ln_Name,199);

        if (diskobj=(GetDiskObject(buf)))  // We release the Disk Object down below!
          image = (struct Image *)diskobj->do_Gadget.GadgetRender;
      }

      if (windata->win = OpenWindowTags(NULL,
          WA_Left,   (scrwidth-winwidth)/2,
          WA_Top,    (scrheight-winheight)/2,
          WA_Width, winwidth,//(TextLength(&scr->RastPort,"Program Name",12)*2) + (TextLength(&scr->RastPort,"Priority",8)*2) + (2 * OUTSIDEBORDER) + scr->WBorLeft + scr->WBorRight,
          WA_Height, winheight,
          WA_AutoAdjust, TRUE,
          WA_Activate, (prefs->Interactive) ? 1 : 0,
          WA_IDCMP,  (prefs->Interactive) ? IDCMP_VANILLAKEY : 0L,
          WA_Flags,  WFLG_SMART_REFRESH | WFLG_ACTIVATE,
          WA_PubScreen, scr,
          WA_PubScreenFallBack, "Workbench",
          WA_SuperBitMap, windata->bitmap,
          TAG_END))
      {
        /* Set Global Pen Numbers */
        if (dri = GetScreenDrawInfo(scr))
        {
          BackgroundPen = dri->dri_Pens[BACKGROUNDPEN];
          HighlightTextPen = dri->dri_Pens[HIGHLIGHTTEXTPEN];
          ShinePen = dri->dri_Pens[SHINEPEN];
          ShadowPen = dri->dri_Pens[SHADOWPEN];
          FreeScreenDrawInfo( scr, dri );
        }

        if (vi=GetVisualInfo(scr,TAG_DONE))
        {
          DrawBevelBox(windata->win->RPort, XOFFSET, 34, windata->win->Width-150, BARHEIGHT, GTBB_Recessed, TRUE, GT_VisualInfo, vi, TAG_DONE);  /* Draw Progress Indicator Box */
          FreeVisualInfo(vi);
        }

        /************************/
        /* Write text to window */
        /************************/
        if (GetVar("Workbench",buffer,7,0)>=0)
          strcat(TitleText,buffer);
        iText.IText = TitleText;
        iText.FrontPen = ShadowPen;
        PrintIText(windata->win->RPort, &iText, ((windata->win->Width-IntuiTextLength(&iText))/2)+1, 16);
        iText.FrontPen = HighlightTextPen;
        PrintIText(windata->win->RPort, &iText, (windata->win->Width-IntuiTextLength(&iText))/2, 15);

        SetAfPt(windata->win->RPort, NULL, 0);

        /********************************/
        /* Make our undo buffer bitmaps */
        /********************************/
        if (windata->bitmap)
        {
          /* icon undo bitmap */
          if (windata->iconundobitmap=AllocBitMap(XOFFSET-windata->win->BorderRight,winheight-(windata->win->BorderTop+windata->win->BorderBottom),GetBitMapAttr(windata->bitmap,BMA_DEPTH),GetBitMapAttr(windata->bitmap,BMA_FLAGS),NULL))
            BltBitMap(windata->bitmap,winwidth-XOFFSET,windata->win->BorderTop,windata->iconundobitmap,0,0,XOFFSET-windata->win->BorderRight,winheight-(windata->win->BorderTop+windata->win->BorderBottom),0x0C0,0xFF,NULL);
          /* filename undo bitmap */
          if (windata->filenameundobitmap=AllocBitMap(winwidth-(2*XOFFSET),winheight-34-BARHEIGHT-windata->win->BorderBottom,GetBitMapAttr(windata->bitmap,BMA_DEPTH),GetBitMapAttr(windata->bitmap,BMA_FLAGS),NULL))
            BltBitMap(windata->bitmap,XOFFSET,34+BARHEIGHT,windata->filenameundobitmap,0,0,winwidth-(2*XOFFSET),winheight-34-BARHEIGHT-windata->win->BorderBottom,0x0C0,0xFF,NULL);
        }

        success=TRUE;
      }

      if (diskobj)
      {
        DrawImage(windata->win->RPort,image,((XOFFSET-windata->win->BorderLeft-image->Width)/2)+windata->win->BorderLeft,((80-image->Height)/2));
        FreeDiskObject(diskobj);
      }

      UnlockPubScreen(NULL,scr);
    }
  }

  if (!success)
  {
    FreeVec(windata);
    windata=NULL;
  }

  return(windata);
}

void CloseProgressWindow(struct ProgressWindowData *data)
{
  CloseWindow(data->win);
  if (data->bitmap)
    FreeBitMap(data->bitmap);
  if (data->iconundobitmap)
    FreeBitMap(data->iconundobitmap);
  if (data->filenameundobitmap)
    FreeBitMap(data->filenameundobitmap);
  FreeVec(data);
}

void UpdateProgressBar(struct Window *win, int current, int total)
{
  int x;
  x = ((win->Width-(2*(XOFFSET+2)))*current/total)+(XOFFSET+2);

  SetAfPt(win->RPort,(UWORD *)&Crosshatch,1);
  SetBPen(win->RPort,ShinePen);
  SetAPen(win->RPort,3);
  RectFill(win->RPort,(XOFFSET+2),35,x,35+BARHEIGHT-3);
}

void ShowIconImage(struct ProgressWindowData *data, struct Image *image)
{
  struct Region *reg;
  struct Region *oldreg;
  struct Rectangle rect;

  if (data->iconundobitmap)
    BltBitMapRastPort(data->iconundobitmap,0,0,data->win->RPort,winwidth-XOFFSET,data->win->BorderTop,XOFFSET-data->win->BorderRight,winheight-data->win->BorderTop-data->win->BorderBottom,0x0C0);
  else
  {
    SetAfPt(data->win->RPort,NULL,0);
    SetAPen(data->win->RPort,BackgroundPen);
    RectFill(data->win->RPort,winwidth-XOFFSET,data->win->BorderTop,winwidth-data->win->BorderRight-1,winheight-data->win->BorderBottom-1);
  }

  rect.MinX=winwidth-XOFFSET;
  rect.MinY=data->win->BorderTop;
  rect.MaxX=winwidth-data->win->BorderRight-1;
  rect.MaxY=winheight-data->win->BorderBottom-1;
  if (reg=NewRegion())
  {
    OrRectRegion(reg,&rect);

    oldreg=InstallClipRegion(data->win->WLayer,reg);

    DrawImage(data->win->RPort,image,(400-XOFFSET)+((XOFFSET-image->Width)/2),((80-image->Height)/2));

    InstallClipRegion(data->win->WLayer,oldreg);

    DisposeRegion(reg);
  }

}





BOOL LoadBitmap(struct WBStartupPrefs *prefs, struct ProgressWindowData *data, struct Screen *scr)
{
  /* Load the picture file with datatypes.library, copy the resulting bitmap and release the file */

  struct FrameInfo *o;   /* This is our datatype object */
  struct BitMapHeader *bmhd=NULL;
  struct BitMap       *bitmap;
  struct gpLayout gpl;
  char   pathname[200];
  BOOL   success=FALSE;

  struct IFFHandle *iffhandle;
  struct CollectionItem *ci;
  LONG ifferror;

  ULONG width, height, xoff, yoff, mapwidth, mapheight;

  /***********************************************************************/
  /* Get the filename of the graphics picture to use from WBPattern.prefs*/
  /***********************************************************************/
  if (!prefs->BackgroundFilename[0])
  {
    if (iffhandle = AllocIFF())
    {
      if (iffhandle->iff_Stream = (LONG)Open("ENV:sys/WBPattern.prefs",MODE_OLDFILE))
      {
        InitIFFasDOS(iffhandle);
        if ((ifferror = OpenIFF(iffhandle,IFFF_READ)) == 0)
        {
          CollectionChunk(iffhandle, ID_PREF, ID_PTRN);

          for(;;)
          {

          ifferror=ParseIFF(iffhandle, IFFPARSE_STEP);
          
          if (ifferror == IFFERR_EOC)
            continue;
          else if (ifferror)
            break;

          if (ci = FindCollection(iffhandle, ID_PREF, ID_PTRN))
            do {
              if ((!(((struct WBPatternPrefs *)ci->ci_Data)->wbp_Flags & WBPF_PATTERN)) && (((struct WBPatternPrefs *)ci->ci_Data)->wbp_Which == prefs->BackgroundType-1))
              {
                strncpy(pathname,(char *)(ci->ci_Data)+sizeof(struct WBPatternPrefs),((struct WBPatternPrefs *)ci->ci_Data)->wbp_DataLength);
                pathname[((struct WBPatternPrefs *)ci->ci_Data)->wbp_DataLength]=0;
              }
              ci = ci->ci_Next;
            } while (ci);
          }
          CloseIFF(iffhandle);
        }
        Close(iffhandle->iff_Stream);
      }
      FreeIFF(iffhandle);
    }
  }
  else
    strcpy(pathname,prefs->BackgroundFilename);

  /*******************************************/
  /* Read the graphics file and get a bitmap */
  /*******************************************/
  if (pathname[0])   /* Do we have a file name to use ? */
  {
    if (o = (struct FrameInfo *)NewDTObject(pathname,
                                            DTA_SourceType,DTST_FILE,
                                            DTA_GroupID,GID_PICTURE,
                                            PDTA_Remap,TRUE,
                                            PDTA_Screen,scr,
                                            TAG_DONE))
    {
      gpl.MethodID = DTM_PROCLAYOUT;
      gpl.gpl_GInfo = NULL;
      gpl.gpl_Initial = 1;

      if (DoMethodA((Object *)o,&gpl))
        GetDTAttrs((Object *)o,
              PDTA_BitMapHeader,&bmhd,
              PDTA_BitMap,&bitmap,
              TAG_DONE);


      /************************************************************/
      /*   Tile the bitmap into a bitmap the size of our window   */
      /************************************************************/
      if (data->bitmap=AllocBitMap(winwidth,winheight,GetBitMapAttr(bitmap,BMA_DEPTH),GetBitMapAttr(bitmap,BMA_FLAGS),NULL))
      {
        mapwidth = bmhd->bmh_Width;
        mapheight = bmhd->bmh_Height;
        yoff = 0;
        while (yoff < winheight)
        {
          xoff=0;
          height = min(mapheight,winheight-yoff);
          while (xoff < winwidth)
          {
            width = min(mapwidth,winwidth-xoff);
            BltBitMap(bitmap,0,0,data->bitmap,xoff,yoff,width,height,0x0C0,0xFF,NULL);
            xoff += width;
          }
          yoff += height;
        }
        success=TRUE;
      }

      DisposeDTObject((Object *)o);
    }
  }

  return(success);
}


BOOL InteractiveRunProgram(struct Window *win)
{
  BOOL runprogram=FALSE;
  struct IntuiMessage *msg;
  BOOL done=FALSE;

  while (!done)
  {
    Wait(1L<<win->UserPort->mp_SigBit);

    while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
    {
      if (msg->Class == IDCMP_VANILLAKEY)
        if (msg->Code=='Y' || msg->Code=='y')
        {
          done=TRUE;
          runprogram = TRUE;
        }
        else if (msg->Code=='N' || msg->Code=='n')
        {
          done=TRUE;
          runprogram = FALSE;
        }
      ReplyMsg((struct Message *)msg);
    }
  }

  return(runprogram);
}

void DisplayProgramName(struct ProgressWindowData *data, char *name, BOOL query)
{
  struct IntuiText iText = { 2,0,0,0,0,NULL,NULL,NULL};
  char *outputbuffer;

  /* Fill the text area with our bitmap or blank space */
  if (data->filenameundobitmap)
    BltBitMapRastPort(data->filenameundobitmap,0,0,data->win->RPort,XOFFSET,34+BARHEIGHT,winwidth-(2*XOFFSET),winheight-34-BARHEIGHT-data->win->BorderBottom,0x0C0);
  else
  {
    SetAfPt(data->win->RPort,NULL,0);
    SetAPen(data->win->RPort,BackgroundPen);
    RectFill(data->win->RPort,XOFFSET,34+BARHEIGHT,winwidth-XOFFSET-1,winheight-data->win->BorderBottom-1);
  }

  if (outputbuffer = AllocVec(strlen(name)+3,MEMF_PUBLIC))
  {
    strcpy(outputbuffer,name);
    if (query)
      strcat(outputbuffer," ?");
    iText.IText = outputbuffer;
    iText.FrontPen = ShadowPen;
    PrintIText(data->win->RPort, &iText, ((data->win->Width-IntuiTextLength(&iText))/2)+1, 34+BARHEIGHT+((data->win->Height-34-BARHEIGHT-data->win->WScreen->Font->ta_YSize)/2)+2+1);
    iText.FrontPen = HighlightTextPen;
    PrintIText(data->win->RPort, &iText, (data->win->Width-IntuiTextLength(&iText))/2, 34+BARHEIGHT+((data->win->Height-34-BARHEIGHT-data->win->WScreen->Font->ta_YSize)/2)+2);
    FreeVec(outputbuffer);
  }
}

