/*
   *
   * $Id: grabwin.c,v 1.3 1998/06/03 14:02:06 Giambattista_Bloisi Exp $
   *
 */

#include "common/extern.h"
#include "common/subtasksupp.h"
#include "common/Subtask.h"
#include "common/Grab_mcc.h"

#include <MUI/NListview_mcc.h>

#include <dos/dostags.h>
#include <exec/memory.h>
#include <exec/semaphores.h>

/* *********************************************** */
/*                                                 */
/*  Grab MUI class.                                */
/*                                                 */
/* *********************************************** */

extern struct SignalSemaphore sub_sema;
extern struct ScanData scanhd;
extern struct MsgPort *myport;
extern struct Library *SocketBase;
int socketopens = 0;

/// "SubTask"
struct SubTask *
SpawnNetTask (char *name, BPTR func, APTR data)
{
  struct SubTask *st;

  if ((st = (struct SubTask *) AllocSPooled (gd.gd_pool, sizeof (struct SubTask))))
    {
      st->st_Reply = myport;
      st->st_Data = data;

      if ((st->st_Task = CreateNewProcTags (NP_Seglist, func,
                                            NP_Name, name,
                                            NP_StackSize, 1024 * 32,
                                            NP_Priority, -1,
                                            NP_Cli, TRUE,
                                  NP_CommandName, "GiambyNetGrabber_module",
                                            NP_Arguments, "start",
                                            TAG_DONE)))
        {
          if (SendSubTaskStartMsg (st, STC_STARTUP, st))
            {
              return (st);
            }
        }

      FreeSPooled (gd.gd_pool, st, sizeof (struct SubTask));
    }
  return (NULL);
}
///

/// "New"

ULONG
mGrab_New (struct IClass * cl, Object * obj, struct opSet * msg)
{
  APTR gauge, scale;
  char procname[100];
// *INDENT-OFF*
  obj = (Object *) DoSuperNew(cl, obj,
          MUIA_Draggable, TRUE,
          MUIA_UserData,  UDB_STOPGRAB,

          Child, gauge = GaugeObject,
                           GaugeFrame,
                           MUIA_HelpNode,       "Gauge Object",
                           MUIA_Gauge_Horiz,    TRUE,
                           MUIA_Gauge_InfoText, "",
                           MUIA_Gauge_Max,      0,
                         End,

          Child, scale = ScaleObject,
                           MUIA_Scale_Horiz, TRUE,
                         End,

          TAG_MORE, msg->ops_AttrList);
// *INDENT-ON*







  if (obj)
    {
      register struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);
      extern struct SignalSemaphore mem_sema;

      //ergo, set data
      //data->self  = obj;
      data->gauge = gauge;
      data->proj = (Object *) GetTagData (MUIA_UrlEditWin_ProjWin, NULL, msg->ops_AttrList);
      data->status = ST_CLEAR;
      InitSemaphore (&data->sema);

      data->hd.sema = &sub_sema;        //&data->sema;

      data->hd.mem_sema = &mem_sema;
      data->hd.pool = gd.gd_pool;
      data->hd.self = obj;
      data->hd.proj = data->proj;
      data->hd.app = (Object *) oa->App;
      data->hd.prefs = prefs;   //secs

      data->hd.pprefs = (struct proj_prefs *) xget (data->proj, MUIA_ProjWin_ProjPrefs);

      data->hd.gd = &gd;
      data->hd.subtask = NULL;

      sprintf (procname, "GNetGrab-Net");

      if ((data->httpfunc = LoadSeg ("PROGDIR:modules/http")))
        {

          if ((data->hd.subtask = SpawnNetTask (procname, data->httpfunc, &data->hd)))
            {
              return ((ULONG) obj);
            }
          else
            error_req (STRING (MSG_OK, "*_OK"), "%s", STRING (ERR_NORUNHTTP, "\033c I can't run: \n \"http module\""));

        }

      D (printf ("error making subtask...\n"));

      CoerceMethod (cl, obj, OM_DISPOSE);
    }
  else
    error_req (STRING (MSG_OK, "*_OK"), "%s", STRING (ERR_NOMEM, "Out of Memory"));

  D (printf ("Grab: new error\n"));

  return (NULL);
}
///

/// "Dispose"
ULONG
mGrab_Dispose (struct IClass * cl, Object * obj, Msg msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);
  struct Message *stm;

  if (data->hd.subtask)
    {
      // first free all queued message!
      while ((stm = (struct Message *) GetMsg (myport)))
           {
             ReplyMsg ((struct Message *) stm);
           }

      KillSubTask (data->hd.subtask);
      Delay (10);
      UnLoadSeg (data->httpfunc);
    }

  return (DoSuperMethodA (cl, obj, msg));
}
///

/// "Setup"
ULONG
mGrab_Setup (struct IClass * cl, Object * obj, struct MUIP_HandleInput * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);

  if (!(DoSuperMethodA (cl, obj, (Msg) msg)))
    return (FALSE);

  /*
     ** set a pointer to our application in our instance data.
     ** this indicates the sub task that we should be notified
     ** when a new line is calculated.
   */

  /*tainSemaphore (data->hd.sema);
     get (obj, MUIA_ApplicationObject, &data->hd.app);
     ReleaseSemaphore (data->hd.sema);
   */

  return (TRUE);
}
///

/// "Cleanup"
ULONG
mGrab_Cleanup (struct IClass * cl, Object * obj, struct MUIP_HandleInput * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);

  /*
     ObtainSemaphore (&data->sema);
     data->app = NULL;
     ReleaseSemaphore (&data->sema);
   */

  return (DoSuperMethodA (cl, obj, (Msg) msg));
}
///

/// "Grab"
ULONG
mGrab_Grab (struct IClass * cl, Object * obj, struct MUIP_Grab_Grab * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);

  if (data->status == ST_CLEAR)
    {
      data->nd = msg->entry;
      msg->entry->status = data->status = ST_GRABBING;

      DoMethod ((Object *) data->proj, MUIM_NList_RedrawEntry, data->nd);

      SendSubTaskMsg (data->hd.subtask, STC_GRABURL, msg->entry);

      return ((ULONG) obj);
    }

  return (NULL);
}
///

/// "Finish"
ULONG
mGrab_Finish (struct IClass * cl, Object * obj, struct MUIP_Grab_Grab * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);
  struct URLNode *nd;
  struct ScanMessage *sm;

  /*
     ObtainSemaphore (data->hd.sema);
     if (data->hd.app == NULL)
     {
     ReleaseSemaphore (data->hd.sema);
     return (NULL);
     }
     ReleaseSemaphore (data->hd.sema);
   */

  nd = data->nd;
  data->status = ST_CLEAR;

  DoMethod (obj, MUIM_Grab_Update, 0, STRING (GRAB_Finished, "Finished"));

  if (nd->depth > 0)
    {
      if (((nd->type ? stricmp (nd->type, "text/html") : 1) == 0))
        {

          if ((sm = (struct ScanMessage *) AllocSPooled (gd.gd_pool, sizeof (struct ScanMessage))))
            {
              sm->proj = data->proj;
              sm->pprefs = data->hd.pprefs;
              sm->nd = nd;
              sm->filename = NULL;

              ObtainSemaphore (&scanhd.lsema);
              AddTail (&scanhd.scanlist, (struct Node *) sm);
              ReleaseSemaphore (&scanhd.lsema);

              Signal (&gd.gd_subtask->st_Task->pr_Task, SIGBREAKF_CTRL_C);
            }
        }
    }

  // This method also refresh the status mode...
  DoMethod ((Object *) data->proj, MUIM_ProjWin_GrabbedNode, data->nd);

  return (NULL);
}
///

/// "Error"
ULONG
mGrab_Error (struct IClass * cl, Object * obj, struct MUIP_Grab_Error * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);
  struct URLNode *nd;

  /*
     ObtainSemaphore (data->hd.sema);
     if (data->hd.app == NULL)
     {
     ReleaseSemaphore (data->hd.sema);
     return (NULL);
     }
     ReleaseSemaphore (data->hd.sema);
   */

  nd = data->nd;
  nd->status = ST_ERROR;
  data->status = ST_CLEAR;

  DoMethod (obj, MUIM_Grab_Update, 0, STRING (GRAB_Error, "Error!"));

  // This method also refresh the status mode...
  DoMethod ((Object *) data->proj, MUIM_ProjWin_GrabbedNode, data->nd);

  return (NULL);
}
///

/// "SetUrl"
ULONG
mGrab_SetUrl (struct IClass * cl, Object * obj, struct MUIP_Grab_SetUrl * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);
  struct URLNode *nd;

  /*
     //ObtainSemaphore (data->hd.sema);
     if (data->hd.app == NULL)
     {
     //ReleaseSemaphore (data->hd.sema);
     return (NULL);
     }
     //ReleaseSemaphore (data->hd.sema);
   */

  nd = data->nd;

  if (msg->type)
    {
      if (nd->type)
        FreeVecPooled (gd.gd_pool, nd->type);
      nd->type = newstrcpy (gd.gd_pool, msg->type);
    }

  if (msg->etag)
    {
      if (nd->etag)
        FreeVecPooled (gd.gd_pool, nd->etag);
      nd->etag = newstrcpy (gd.gd_pool, msg->etag);
    }

  if (msg->date)
    memcpy (&nd->date, msg->date, sizeof (struct DateStamp));

  nd->size = msg->size;
  nd->status = msg->status;

  return (NULL);
}
///

/// "Update"
ULONG
mGrab_Update (struct IClass * cl, Object * obj, struct MUIP_Grab_Update * msg)
{
  struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);

  set (data->gauge, MUIA_Gauge_Current, msg->percent);

  if (msg->message)
    set (data->gauge, MUIA_Gauge_InfoText, msg->message);

  return (NULL);
}
///

/// "Set"
ULONG
mGrab_Set (struct IClass * cl, Object * obj, Msg msg)
{
  register struct GrabData *data = (struct GrabData *) INST_DATA (cl, obj);

  struct TagItem *tags, *tag;
  for (tags = ((struct opSet *) msg)->ops_AttrList; (tag = (struct TagItem *) NextTagItem (&tags));)
    {
      switch (tag->ti_Tag)
        {
        case MUIA_Grab_Finish:
          ObtainSemaphore (data->hd.sema);
          data->hd.app = NULL;
          ReleaseSemaphore (data->hd.sema);

          if (data->status == ST_GRABBING)
            {
              Signal (&data->hd.subtask->st_Task->pr_Task, SIGBREAKF_CTRL_C);

              if (data->nd)
                data->nd->status = ST_ERROR;    // interrupted!

            }
          break;

        case MUIA_Grab_Stop:
          if (data->status == ST_GRABBING)
            {
              D (printf ("Stop msg\n"));
              Signal (&data->hd.subtask->st_Task->pr_Task, SIGBREAKF_CTRL_C);

              if (data->nd)
                data->nd->status = ST_ERROR;    // interrupted!

            }
          break;

        case MUIA_Gauge_Max:
          set (data->gauge, MUIA_Gauge_Max, tag->ti_Data);
          break;

        }
    }

  return (DoSuperMethodA (cl, obj, msg));

}
///

/// "Dispatcher"
SAVEDS (ULONG)
Grab_Dispatcher (REG (a0, struct IClass * cl), REG (a2, Object * obj), REG (a1, Msg msg))
{
  switch (msg->MethodID)
    {
    case OM_NEW:
      return ((ULONG) mGrab_New (cl, obj, (struct opSet *) msg));
    case OM_DISPOSE:
      return ((ULONG) mGrab_Dispose (cl, obj, (Msg) msg));
    case OM_SET:
      return ((ULONG) mGrab_Set (cl, obj, (Msg) msg));

    case MUIM_Setup:
      return ((ULONG) mGrab_Setup (cl, obj, (struct MUIP_HandleInput *) msg));
    case MUIM_Cleanup:
      return ((ULONG) mGrab_Cleanup (cl, obj, (struct MUIP_HandleInput *) msg));

      //case MUIM_DragDrop   : return ( (ULONG) mGrab_DragDrop(cl, obj, (struct MUIP_DragDrop    *) msg));
      //case MUIM_DragQuery  : return ( (ULONG) mGrab_DragDrop(cl, obj, (struct MUIP_DragDrop    *) msg));

    case MUIM_Grab_Update:
      return ((ULONG) mGrab_Update (cl, obj, (struct MUIP_Grab_Update *) msg));
    case MUIM_Grab_Grab:
      return ((ULONG) mGrab_Grab (cl, obj, (struct MUIP_Grab_Grab *) msg));
    case MUIM_Grab_Finish:
      return ((ULONG) mGrab_Finish (cl, obj, (struct MUIP_Grab_Grab *) msg));
    case MUIM_Grab_Error:
      return ((ULONG) mGrab_Error (cl, obj, (struct MUIP_Grab_Error *) msg));
    case MUIM_Grab_SetUrl:
      return ((ULONG) mGrab_SetUrl (cl, obj, (struct MUIP_Grab_SetUrl *) msg));

      //case MUIM_Grab_Stop  : return ( (ULONG) mGrab_Stop (cl,obj, (struct MUIP_Grab_Grab *) msg));
    }
  return (DoSuperMethodA (cl, obj, msg));
}
///



/* *********************************************** */
/*                                                 */
/*  WinGrab MUI class.                             */
/*                                                 */
/* *********************************************** */

/// "New"
ULONG
mWinGrab_New (struct IClass * cl, Object * obj, struct opSet * msg)
{
  APTR *gauges, group;

  if (!SocketBase)
    SocketBase = OpenLibrary ("bsdsocket.library", 0);

  if (SocketBase)
    {
      ObtainSemaphore (&prefs->sema);
      gauges = (APTR *) AllocVecPooled (gd.gd_pool, sizeof (APTR) * 17);
      ReleaseSemaphore (&prefs->sema);

      if (gauges)
        {
          gauges[1] = NULL;
          /*
             Aaargh!!!! Grosso errore: se si cambiano le impostazioni il buffer puņ essere valicato.
           */
// *INDENT-OFF*
  obj = (Object *) DoSuperNew (cl, obj,
                                //MUIA_Window_Title, STRING (GW_Title, "Grabbing..."),
                                 MUIA_Window_ID, MAKE_ID('G','W','I','N'),
                                 MUIA_Window_NoMenus, TRUE,
                                 MUIA_HelpNode, "WIN_GRAB",

                                 WindowContents, group = VGroup,
                                 End,

                              TAG_MORE, msg->ops_AttrList);
// *INDENT-ON*







          if (obj)
            {
              register struct WinGrabData *data = (struct WinGrabData *) INST_DATA (cl, obj);

              //ergo, set data
              data->self = obj;
              data->parent = (APTR) GetTagData (MUIA_UrlEditWin_ProjWin, NULL, msg->ops_AttrList);
              data->group = group;
              data->urls = gauges;
              data->pprefs = (struct proj_prefs *) xget ((Object *) data->parent, MUIA_ProjWin_ProjPrefs);

              {                 // Now setting window title...

                char *parenttitle, *newtitle = NULL;

                get (data->parent, MUIA_Window_Title, &parenttitle);

                if (parenttitle)
                  if ((newtitle = (char *) AllocVecPooled (gd.gd_pool, strlen (parenttitle) + strlen (STRING (GRAB_Wintitle, "%s - Grab Window")))))
                    sprintf (newtitle, STRING (GRAB_Wintitle, "%s - Grab Window"), parenttitle);

                if (!newtitle)
                  if ((newtitle = (char *) AllocVecPooled (gd.gd_pool, 2 + strlen (STRING (GRAB_Wintitle, "%s - Grab Window")))))
                    sprintf (newtitle, STRING (GRAB_Wintitle, "%s - Grab Window"), "??");

                set (obj, MUIA_Window_Title, newtitle);
                data->title = newtitle;
              }

              socketopens++;

              DoMethod ((Object *) oa->App, OM_ADDMEMBER, obj);

              gauges[0] = GrabObject,
                MUIA_UrlEditWin_ProjWin, data->parent,
                End;

              if (gauges[0])
                {
                  DoMethod ((Object *) group, OM_ADDMEMBER, gauges[0]);
                  set (obj, MUIA_Window_Open, TRUE);

                  return ((ULONG) obj);
                }


              // Fails ?
              CoerceMethod (cl, obj, OM_DISPOSE);
            }
          else
            error_req (STRING (MSG_OK, "*_OK"), "%s", STRING (ERR_NOMEM, "Out of Memory"));
        }
    }
  else
    error_req (STRING (MSG_OK, "*_OK"), "%s", STRING (ERR_NOSOCKET, "You must first run TCP/IP stack!"));

  D (printf ("GrabWin: new error\n"));

  return (NULL);
}
///

/// "Dispose"
ULONG
mWinGrab_Dispose (struct IClass * cl, Object * obj, Msg msg)
{
  struct WinGrabData *data = (struct WinGrabData *) INST_DATA (cl, obj);

  for (int i = 0; data->urls[i] != NULL; i++)
    {
      set ((Object *) data->urls[i], MUIA_Grab_Finish, TRUE);
    }

  if (data->urls)
    FreeVecPooled (gd.gd_pool, data->urls);

  if (data->title)
    FreeVecPooled (gd.gd_pool, data->title);

  if (SocketBase)
    {
      if (--socketopens < 1)
        {
          CloseLibrary (SocketBase);
          SocketBase = NULL;
        }
    }

  DoMethod ((Object *) oa->App, OM_REMMEMBER, obj);

  return (DoSuperMethodA (cl, obj, msg));
}
///

/// "Set"
ULONG
mWinGrab_Set (struct IClass * cl, Object * obj, Msg msg)
{
  register struct WinGrabData *data = (struct WinGrabData *) INST_DATA (cl, obj);

  struct TagItem *tags, *tag;
  for (tags = ((struct opSet *) msg)->ops_AttrList; (tag = (struct TagItem *) NextTagItem (&tags));)
    {
      switch (tag->ti_Tag)
        {
        case MUIA_Window_CloseRequest:
          if (tag->ti_Data == TRUE)
            {
              for (int i = 0; data->urls[i] != NULL; i++)
                {
                  set ((Object *) data->urls[i], MUIA_Grab_Finish, TRUE);
                }

              set (data->parent, MUIA_ProjWin_Grabwin, NULL);
              // First do nothing for clearing message ports!
              DoMethod ((Object *) oa->App, MUIM_Application_PushMethod, obj, 3, MUIM_Set, MUIA_Window_Open, 0);
              DoMethod ((Object *) oa->App, MUIM_Application_PushMethod, obj, 2, OM_DISPOSE, NULL);
              return (NULL);
            }
          break;

        }
    }

  return (DoSuperMethodA (cl, obj, msg));
}
///

/// "AddUrl"
ULONG
mWinGrab_AddUrl (struct IClass * cl, Object * obj, struct MUIP_WGrab_AddUrl * msg)
{
  struct WinGrabData *data = (struct WinGrabData *) INST_DATA (cl, obj);
  struct URLNode *nd = msg->entry;
  BOOL newsock = TRUE;
  int i;

  nd = (struct URLNode *) data->list->mlist.mlh_Head;

  while (nd->status != ST_CLEAR)
    {
      nd = (struct URLNode *) nd->un_node.mln_Succ;

      if (nd->un_node.mln_Succ == NULL)
        return (NULL);
    }

  for (i = 0; data->urls[i] != NULL && newsock; i++)
    {
      if (DoMethod ((Object *) data->urls[i], MUIM_Grab_Grab, nd))
        {
          newsock = FALSE;
          DoMethod ((Object *) data->list->projwin, MUIM_NList_RedrawEntry, nd);
        }
    }
  ObtainSemaphore (&data->pprefs->sema);
  if (newsock && (i < data->pprefs->socknum))
    {
      ReleaseSemaphore (&data->pprefs->sema);
      if ((data->urls[i] = GrabObject,
           MUIA_UrlEditWin_ProjWin, data->parent,
           End))
        {
          data->urls[i + 1] = NULL;

          DoMethod ((Object *) data->group, MUIM_Group_InitChange);

          DoMethod ((Object *) data->group, OM_ADDMEMBER, data->urls[i]);
          DoMethod ((Object *) data->urls[i], MUIM_Grab_Grab, nd);

          DoMethod ((Object *) data->group, MUIM_Group_ExitChange);
        }

    }
  else
    ReleaseSemaphore (&data->pprefs->sema);
  //else D(printf("I can't allocate new socket!\n"));


  return (TRUE);
}
///

/// "RemUrl"
ULONG
mWinGrab_RemUrl (struct IClass * cl, Object * obj, struct MUIP_WGrab_RemUrl * msg)
{
  struct WinGrabData *data = (struct WinGrabData *) INST_DATA (cl, obj);
  int i;

  if (!msg->entry)
    {
      for (i = 0; data->urls[i] != NULL; i++)
        {
          set ((Object *) data->urls[i], MUIA_Grab_Stop, TRUE);
        }
    }
  else
    {
      set ((Object *) msg->entry, MUIA_Grab_Stop, TRUE);
    }

  return (TRUE);
}
///

/// "StartGrab"
ULONG
mWinGrab_StartGrab (struct IClass * cl, Object * obj, struct MUIP_WGrab_StartGrab * msg)
{
  struct WinGrabData *data = (struct WinGrabData *) INST_DATA (cl, obj);
  struct URLNode *nd;

  data->list = msg->ulist;

  nd = (struct URLNode *) data->list->mlist.mlh_Head;

  while (nd->un_node.mln_Succ)
    {
      if (nd->status == ST_CLEAR)
        DoMethod (obj, MUIM_WGrab_AddUrl, nd);
      nd = (struct URLNode *) nd->un_node.mln_Succ;
    }

  return ((ULONG) DoMethod (obj, MUIM_WGrab_AddUrl, NULL));

  return (TRUE);
}
///

/// "Dispatcher"
SAVEDS (ULONG)
WinGrab_Dispatcher (REG (a0, struct IClass * cl), REG (a2, Object * obj), REG (a1, Msg msg))
{
  switch (msg->MethodID)
    {

    case OM_NEW:
      return ((ULONG) mWinGrab_New (cl, obj, (struct opSet *) msg));
    case OM_DISPOSE:
      return ((ULONG) mWinGrab_Dispose (cl, obj, (Msg) msg));
    case OM_SET:
      return ((ULONG) mWinGrab_Set (cl, obj, (Msg) msg));

    case MUIM_WGrab_AddUrl:
      return ((ULONG) mWinGrab_AddUrl (cl, obj, (struct MUIP_WGrab_AddUrl *) msg));
    case MUIM_WGrab_RemUrl:
      return ((ULONG) mWinGrab_RemUrl (cl, obj, (struct MUIP_WGrab_RemUrl *) msg));

    case MUIM_WGrab_StartGrab:
      return ((ULONG) mWinGrab_StartGrab (cl, obj, (struct MUIP_WGrab_StartGrab *) msg));

    }
  return (DoSuperMethodA (cl, obj, msg));
}
///

















//
