/*
  TM: A Bars and Pipes Transport Monitor tool.
  
  Copyright (C) 1997 Richard Hagen
  This code is released into the Public Domain, and may be freely
  distributed in its original form.
  
  It is supplied ``as is'', and comes with no warranty.
  This program code was released because it might be useful as a
  starting point for other programmers. However, if any damage arises
  from its use, the original author will not be held liable.
  
  You are free to use and modify this code to your heart's content,
  provided you acknowledge me as the original author in any code
  that you might distribute which is based largely on this code.
  
  I acknowledge that the design of this accessory is influenced
  strongly by the example code supplied with the Rules for Tools
  package. However, I have made substantial contributions of my
  own.
  
  Richard Hagen
  R.Hagen@mailbox.uq.edu.au
  
  History:
  	Version 1.0 (13 September 1997)
        Initial release.
*/

#include <libraries/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <exec/memory.h>
#include <string.h>
#include <intuition/intuition.h>
#include <intuition/sghooks.h>

#include "bars.h"
#include "myheader.h"

#define TM_NAME "Transport Monitor"

#define ID_TM MAKE_IDS("TMON")

#define TM_TYPE (TOOL_INPUT | TOOL_NOTPAD)

__chip static UWORD tm[] = { 
  /*------ plane # 0: --------*/
  0x0, 0x0,
  0x3fff, 0xfc00,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x2000, 0x0400,
  0x3fff, 0xfc00,
  0x0, 0x0,

  /*------ plane # 1: --------*/
  0x0, 0x0,
  0x0, 0x0,
  0x1fff, 0xfc00,
  0x101b, 0xec00,
  0x1ef9, 0xcf00,
  0x1efa, 0xaf00,
  0x1efb, 0x6f00,
  0x1efb, 0xef00,
  0x1efb, 0xec00,
  0x1fff, 0xfc00,
  0x1fff, 0xfc00,
  0x0, 0x0,

  /*------ plane # 2: --------*/
  0x0, 0x0,
  0x0, 0x0,
  0x0, 0x0,
  0x0fe4, 0x1000,
  0x0106, 0x3000,
  0x0105, 0x5000,
  0x0104, 0x9000,
  0x0104, 0x1000,
  0x0104, 0x1000,
  0x0, 0x0,
  0x0, 0x0,
  0x0, 0x0,

};

static struct Image tm_image = {
  0,0,
  24 , 12 , 3 ,
  &tm[0],
  0x1f,0x00,
  NULL
};	

/* Length of a transport commmand name string. */
#define TC_NAME_LENGTH 13

/* Strings for the names of the transport commands. */
char *tc_names[8] = {
  "            ",	/* There is no transport command 0 */
  "TC_START    ",
  "TC_STOP     ",
  "TC_POSITION ",
  "TC_RECORDON ",
  "TC_RECORDOFF",
  "TC_PLAY     ",
  "TC_TICK     "
  };
    
/* For storing output information. */
struct Line {
  char command[TC_NAME_LENGTH];		/* String for transport command. */
  char start[MBC_STRING_LENGTH];	/* String for the start time. */
  char end[MBC_STRING_LENGTH];		/* String for the end time. */
};

/* Number of lines of output. */
#define NUM_LINES 20

#define WINDOW_HEIGHT (NUM_LINES * 10) + 15

struct TMTool {
  struct Tool tool;

  struct Line lines[NUM_LINES];		/* The lines of output. */
};

extern struct Functions *functions;

static void
  tm_tool_init(struct TMTool *tool)
{
  tool->tool.touched = TOUCH_INIT;

  for (int i = 0;
       i < NUM_LINES;
       i++)
    {
      strcpy(tool->lines[i].command, tc_names[0]);
      for (int j = 0;
	   j < MBC_STRING_LENGTH - 1;
	   j++)
	{
	  tool->lines[i].start[j] = ' ';
	  tool->lines[i].end[j] = ' ';
	}
      tool->lines[i].start[MBC_STRING_LENGTH - 1] = '\0';
      tool->lines[i].end[MBC_STRING_LENGTH - 1] = '\0';
    }
}

static struct ToolMaster master;

static void
display_lines(struct TMTool *tool)
{
  /* Needs to be able to hold the strings plus 2 spaces. */
  char string[TC_NAME_LENGTH + 2 * MBC_STRING_LENGTH];
  
  struct RastPort *rp = tool->tool.window->RPort;
  
  SetAPen(rp, 1);
  SetBPen(rp, 0);
  SetDrMd(rp, JAM2);
  
  for (int i = 0;
       i < NUM_LINES;
       i++)
    {
      sprintf(string, "%s %s %s",
	      tool->lines[i].command,
	      tool->lines[i].start,
	      tool->lines[i].end);
      
      Move(rp, 7, WINDOW_HEIGHT - 5 - i * 10);
      
      Text(rp, string, TC_NAME_LENGTH + 2 * MBC_STRING_LENGTH - 1);
    }
}

/* Update and display commands if necessary. */
static void
  transporttrack(struct Track *track,	/* Track where the TMTool is located. */
		 const long command,	/* Transport command. */
		 const long start,	/* Start time for command. */
		 const long end)	/* End time for command. */
{
  struct TMTool *tool = (struct TMTool *) track->toollist;

  /* Copy down the old information. */
  for (int i = NUM_LINES - 1;
       i > 0;
       i--)
    {
      tool->lines[i] = tool->lines[i - 1];
    }

  /* Update the info in the first line. */
  strcpy(tool->lines[0].command, tc_names[command]);
  (*functions->timetostring)(&(track->clip), start, tool->lines[0].start);
  (*functions->timetostring)(&(track->clip), end, tool->lines[0].end);

  /* Display the info if the window is open. */
  if (tool->tool.window)
    {
      display_lines(tool);
    }
}

/* Called whenever something happens in the transport. */
__geta4			/* Callback. */
void transportcode(long command,	/* Transport command. */
		   long start,		/* Start time for command. */
		   long end)		/* End time for command. */
{
  /* Are we in multiple input mode? */
  if (functions->multiin)
    {
      /* Find all the TMTools and get them to do their thing. */
      for (struct Track *track = (struct Track *) functions->tracklist;	
	   track;
	   track = track->next)
	{
	  struct Tool *tool = (struct Tool *) track->toollist;
	  if (tool && (tool->toolid == ID_TM))
	    {
	      transporttrack(track, command, start, end);
	    }
	}
    }
  else
    {
      /* Get the current input track, and if it has a TMTool, send it
	 the command. */
      struct Track *track = master.intrack;
      if (track)
	{
	  struct Tool *tool = track->toollist;
	  if (tool && (tool->toolid == ID_TM))
	    {
	      transporttrack(track, command, start, end);
	    }
	}
    }
}

/* Process notes. */
__geta4			/* Callback. */
struct Event *
  processeventcode(struct Event *event)
{
  event->tool = event->tool->next; 	/* Doesn't do anything! */
  return(event);
}

struct NewWindow TMNewWindowStructure1 = {
  20, 20,
  305, WINDOW_HEIGHT,
  0,6,
  GADGETDOWN+GADGETUP+CLOSEWINDOW,
  WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,
  NULL,
  NULL,
  "Transport Monitor",
  NULL,
  NULL,
  5,5,
  -1,-1,
  CUSTOMSCREEN
};

/* Interface driver called by Bars and Pipes. */
__geta4		/* Callback. */
void edittoolcode(struct TMTool *tool)
{
  struct IntuiMessage *message;
  struct Window *window;
  long class, code;
  struct Gadget *gadget;
  struct NewWindow *newwindow;
  long refresh = 1;

  if (!tool->tool.touched)
    {
      tm_tool_init(tool);
    }
  
  TMNewWindowStructure1.Screen = functions->screen;
  
  if (tool->tool.touched & TOUCH_EDIT)
    {
      TMNewWindowStructure1.LeftEdge = tool->tool.left;
      TMNewWindowStructure1.TopEdge = tool->tool.top;
    }
  
  newwindow = (struct NewWindow *)
    (*functions->DupeNewWindow)(&TMNewWindowStructure1);
  if (!newwindow)
    {
      return;
    }
  newwindow->Title = 0;
  newwindow->Flags |= BORDERLESS;
  newwindow->Flags &= ~0xF;
  newwindow->BlockPen = 0;
  newwindow->DetailPen = 0;

  window = (struct Window *) (*functions->FlashyOpenWindow)(newwindow);
  if (window == NULL)
    {
      return;
    }
  
  tool->tool.window = window;

  /* Make the various gadgets look pretty. */
  (*functions->EmbossWindowOn)(window,WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG,
			       TM_NAME, (short)-1, (short)-1, 0, 0);

  display_lines(tool);

  /* Process messages until a CLOSEWINDOW. */
  for (;;)
    {
      message = (struct IntuiMessage *) (*functions->GetIntuiMessage)(window);
      class = message->Class;
      code = message->Code;
      gadget = (struct Gadget *) message->IAddress;
      class = (*functions->SystemGadgets)(window,class,gadget,code);

      ReplyMsg((struct Message *)message);
      
      if (class == CLOSEWINDOW)
	{
	  break;	/* ... out of the for(;;) loop. */
	}
      else if (class == GADGETDOWN)
	{
	  /* Nothing. */
	}
      else if (class == GADGETUP)
	{
	  /* Nothing. */
	}
    }
  tool->tool.window = 0;
  tool->tool.left = window->LeftEdge;
  tool->tool.top = window->TopEdge;
  tool->tool.width = window->Width;
  tool->tool.height = window->Height;
  tool->tool.touched = TOUCH_INIT | TOUCH_EDIT;

  (*functions->EmbossWindowOff)(window);
  (*functions->FlashyCloseWindow)(window);
  (*functions->DeleteNewWindow)(newwindow);
}

/* Make sure we remove the transport routine. */
__geta4		/* Callback. */
void removetool()
{
  (*functions->removetransport)(transportcode);
}

struct ToolMaster *
  inittoolmaster()
{
  memset((char *)&master,0,sizeof(struct ToolMaster));
  master.toolid = ID_TM;
  master.image = &tm_image;
  strcpy(master.name, TM_NAME);
  master.edittool = (void_prototype) edittoolcode;
  master.processevent = (event_prototype) processeventcode;
  master.tooltype = TM_TYPE;
  master.removetool = removetool;
  master.toolsize = sizeof(struct TMTool);
  (*functions->installtransport)(transportcode);
  return(&master);
}
