/*
 * Copyright 1988, 1989, 1990, 1991 Massachusetts Institute of Technology
 */
#ifdef SEAMLESS

#include "Glib.h"
#include "GSeamless.h"

extern short DEBUG;

List *curList = NULL;

static G_INT32 protomaj = -1;

static void FreeClip (clip)
     Clip *clip;
{
  if (clip != NULL)
    free (clip);
}

static void FreeSwitch (swtch)
     Swtch *swtch;
{
  if (swtch != NULL)
    free (swtch);
}

static int GetClipNo (clip)
     Clip *clip;

{
  int pos = 1;
  Clip *c = curList->clips;

  if (clip == NULL) return (0);

  while (c != clip && c->next != NULL) {
    c = c->next;
    pos++;
  }

  return (pos);
}

int SeamlessClipNo (list,clip)
     Clip *clip;
     List *list;

{
  int pos = 1;
  Clip *c = list->clips;

  if (clip == NULL) return (0);

  while (c != clip && c->next != NULL) {
    c = c->next;
    pos++;
  }

  return (pos);
}

static int CompareSwitches (s1,s2)
     Swtch *s1,*s2;

{
  return ( (s1->frame == s2->frame) &&
	   (s1->in == s2->in || s1->in == NULL || s2->in == NULL) &&
	   (s1->out == s2->out || s1->out == NULL || s2->out == NULL));
}

/* create a new list to work with */
List *SeamlessCreateList()
{
  List *list;

  list = (List *) calloc (sizeof(List),1);
  return (list);
}


/* free a current list */
void SeamlessFree(s,list, recursive)
        Server *s;
	List *list;
        int recursive;
{
  Clip *clip = list->clips, *oldc;
  Swtch *sw = list->switches, *olds;

  if (recursive)
    while (clip != NULL) {
      oldc = clip->next;
      FreeClip (clip);
      clip = oldc;
    }

  if  (recursive)
    while (sw != NULL) {
      olds = sw->next;
      FreeSwitch (sw);
      sw = olds;
    }

  GFreeList (s->fd, list->key);
  free (list);
}


/* add a clip */
int SeamlessAddClip(list,clip)
	List *list;
	Clip *clip;
{


  Clip *c;

  if (clip == NULL || list == NULL) return (-1);
  list->numClips++;
  clip->next = NULL;


  if (list->numClips == 1) {
    list->clips = clip;
    return (list->numClips);
  }

  c = list->clips;
  if (clip->frame < c->frame) {
    clip->next = list->clips;
    list->clips = clip;
    return (list->numClips);
  }

  while (c->next != NULL) {
    if (c->next->frame > clip->frame) {
      clip->next = c->next;
      c->next = clip;
      return (list->numClips);
    }
    c = c->next;
  }

  c->next = clip;
  return (list->numClips);
}

  
/* add a switch */
int SeamlessAddSwitch(list,swtch)
	List *list;
	Swtch *swtch; /* switch is a reserved word */

{
  Swtch *s;

  if (swtch == NULL || list == NULL) return (-1);
  list->numSwitches++;
  swtch->next = NULL;

  if (list->numSwitches == 1) {
    list->switches = swtch;
    return (list->numSwitches);
  }

  s = list->switches;
  if (swtch->frame < s->frame) {
    swtch->next = list->switches;
    list->switches = swtch;
    return (list->numSwitches);
  }

  while (s->next != NULL) {
    if (s->next->frame > swtch->frame) {
      swtch->next = s->next;
      s->next = swtch;
      return (list->numSwitches);
    }
    s = s->next;
  }
  s->next = swtch;
  return (list->numSwitches);
}

/* remove a switch */
int SeamlessRemoveSwitch (list, s)
     List *list;
     Swtch *s;

{
  Swtch *sw;

  if (list == NULL) return (-1);
  if (list->numSwitches == 0) return (-1);

  sw = list->switches;
  if (sw == s) {
    list->switches = sw->next;
    list->numSwitches--;
    return (0);
  }

  while (sw->next != NULL) {
    if (sw->next == s) {
      sw->next = s->next;
      list->numSwitches--;
      return (0);
    }
    sw = sw->next;
  }

  return (-1);
}


/* remove a clip */
int SeamlessRemoveClip (list, clip)
     List *list;
     Clip *clip;

{
  Clip *c;

  if (list == NULL) return (-1);
  if (list->numClips == 0) return (-1);

  c = list->clips;
  if (c == clip) {
    list->clips = clip->next;
    list->numClips--;
    return (0);
  }

  while (c->next != NULL) {
    if (c->next == clip) {
      c->next = clip->next;
      list->numClips--;
      return (0);
    }
    c = c->next;
  }

  return (-1);
}


/* create a clip */
Clip *SeamlessCreateClip(time, volume, in, out, speed)
	char *volume;
	int time, in, out, speed; /* time is frames from start */
{
  Clip *clip = (Clip *) calloc (sizeof(Clip), 1);
  
  if (clip == NULL) return (clip);

  clip->frame = time;
  printf ("%s: %d\n",volume, strlen(volume));
  clip->volumename = (char *) malloc (strlen (volume)+1);
  strcpy (clip->volumename,volume);
  clip->in = in;
  clip->out = out;
  clip->speed = speed;
  clip->resource = -1;
  return (clip);
}

/* create a clip */
Clip *SeamlessCreateServerClip(time, name, volume, resource, in, out, speed)
	int volume, resource;
	int time, in, out, speed; /* time is frames from start */
        char *name;
{
  Clip *clip = (Clip *) calloc (sizeof(Clip), 1);
  
  if (clip == NULL) return (clip);

  clip->frame = time;
  clip->volume = volume;
  clip->volumename = (char *) malloc (strlen (name) + 1);
  strcpy (clip->volumename,name);
  clip->resource = resource;
  clip->in = in;
  clip->out = out;
  clip->speed = speed;
  return (clip);
}

/* create a switch */
Swtch *SeamlessCreateSwitch(time, in, out, mask)
	Clip *in, *out; /* in and out clips */
	int time, mask; /* time is frames from start */
{
  Swtch *swtch = (Swtch *) calloc (sizeof (Swtch), 1);
  
  if (swtch == NULL) return (swtch);

  swtch->frame = time;
  swtch->mask = mask;
  swtch->in = in;
  swtch->out = out;
  return (swtch);
}


int SeamlessClipDuration (clip)
     Clip *clip;
{
  if (clip == NULL) return 0;

  return ( (clip->out - clip->in) * 30 / clip->speed);
}


Clip *SeamlessTopClip (list, time, channel)
	List *list;
	int time;
        int channel;

{
  Clip *top = NULL, *curClip;
  Swtch *curSwitch, *repSwitch;


  if (list == NULL) 
    return (NULL);
  if (list->numClips == 0 || list->numSwitches == 0) 
    return (NULL);

  curClip = list->clips;
  while (curClip != NULL) {
    if (curClip->frame > time ||
	curClip->frame + SeamlessClipDuration(curClip) < time) {
      curClip = curClip->next;
      continue;
    }

    curSwitch = list->switches;
    while (curSwitch != NULL) {
      if (curSwitch->out != curClip) {
	curSwitch = curSwitch->next;
	continue;
      }

      if ((curSwitch->mask & channel) == 0) {
	curSwitch = curSwitch->next;
	continue;
      }

      if (curSwitch->frame > time) {
	curSwitch = curSwitch->next;
	continue;
      }

      repSwitch = curSwitch->next;
      while (repSwitch != NULL) {
	if ( (repSwitch->in == curClip) &&
	    ((repSwitch->mask & channel) > 0) &&
	    (repSwitch->frame >= time)) {
	  top = curClip;
	  break;
	}
	repSwitch = repSwitch->next;
      }
      if (top == curClip) break;
      curSwitch = curSwitch->next;
    }
    curClip = curClip->next;
  }
  return (top);
}


void SeamlessLength (list, mask, in, out)
     List *list;
     int mask, *in, *out;
{
  Swtch *s;

  *in = COULDNT_DO_FUNC; 
  *out = 0;
  if (list == NULL) return;

  s = ListSwitches(list);
  while (s != NULL) {
    if ( (SwitchMask(s) & mask) && (SwitchOutClip(s)) && 
	(SwitchFrame(s) < *in))
      *in = SwitchFrame(s);

    if ( (SwitchMask(s) & mask) && (SwitchInClip(s)) && 
	(SwitchFrame(s) > *out))
      *out = SwitchFrame(s);

    s = SwitchNext(s);
  }
}


Clip *SeamlessFindClip (list, num)
     List *list;
     int num;

{
  int pos = 1;
  Clip *cur = list->clips;

  if (list == NULL || num <= 0) return (NULL);

  for (pos = 1; pos < num; pos++)
    if (cur == NULL) {
      return (NULL);
    } else {
      cur = cur->next;
    }

  return (cur);
}
  

/* Optimize List -- Whee!!! */
void SeamlessOptimize (list)
	List *list;

{
  Swtch *s1, *s2;

  if (list == NULL) return;
  if (list->numClips == 0 || list->numSwitches == 0) return;

  /* remove NULL switches... */
  s1 = list->switches;
  while (s1 == list->switches) {
    if (s1->mask == 0 || s1->in == s1->out) {
      list->numSwitches--;
      list->switches = s1->next;
      FreeSwitch (s1);
      if (list->numSwitches == 0) return;
      s1 = list->switches;
    } else {
      s1 = NULL;
    }    
  }

  s1 = list->switches;

  while (s1->next != NULL) {
    s2 = s1->next;
    if (s2->mask == 0 || s2->in == s2->out) {
      s1->next = s2->next;
      list->numSwitches--;
      FreeSwitch (s2);
      if (list->numSwitches == 0) return;
    } else {
      s1 = s1->next;
    }
    if (s1 == NULL) break;
  }

  /* remove identical switches... */
  s1 = list->switches;
  while (s1->next != NULL) {
    s2 = s1->next;
    if (CompareSwitches (s1,s2)) {
      s1->next = s2->next;
      list->numSwitches--;
      s1->mask = s1->mask | s2->mask;
      if (s1->in == NULL) s1->in = s2->in;
      if (s1->out == NULL) s1->out = s2->out;
      FreeSwitch (s2);
      if (list->numSwitches == 0) return;
    } else {
      s1 = s1->next;
    }
    if (s1 == NULL) break;
  }
}

/* Find Current List */
List *SeamlessCurrent (list)
{
  return (curList);
}

/* make a new current list */
SeamlessMakeCurrent (list)
	List *list; 
{
  curList = list;
}

/* play current list, downloading if needed */
SeamlessPlayback (msgsock, list)
     Server *msgsock;
     List *list;
{
  Clip *cl;
  Swtch *sw;
  int i;
  G_INT32 thismajor;

  curList = list;
  if (curList == NULL) return (-1);
  
  /* send initial packet */
  printf ("downloading %d shots and %d switches\n",list->numClips, list->numSwitches);
  if (protomaj == -1 && msgsock->ex4 > 24) {
    protomaj = GExtensionMajor(msgsock, "Seamless editing");
    if (protomaj == NO_EXTENSION) return NO_EXTENSION;
    thismajor = protomaj;
  }
  else thismajor = G_Download;

  if (SendCommand (msgsock->fd, thismajor, list->numClips, list->numSwitches,
		   0,0,0,0,0,0,G_Download) == -1)
    return (_handleerror(msgsock,GIO_ERROR));

  /* download clips */
  cl = curList->clips;
  for (i = 0; i < curList->numClips; i++) {
    send_clip (msgsock,cl);
    cl = cl->next;
  }

  /* download switches */
  sw = curList->switches;
  for (i = 0; i < curList->numSwitches; i++) {
    send_switch (msgsock,sw);
    sw = sw->next;
  }

  printf ("waiting for byte from server...\n");
  full_read (msgsock->fd, &(curList->key), 4);
  curList->key = ntohl (curList->key);
  printf ("returning... %d\n",curList->key);
}

send_clip (s,cl)
     Server *s;
     Clip *cl;
{
  int xmit[5], snd[5];

  if (cl == NULL) {
    xmit[0] = xmit[1] = xmit[2] = xmit[3] = xmit[4] = END_OF_TRANSMISSION;
  } else {
    xmit[0] = cl->frame;
    xmit[1] = GWhichVolumeIndex (s,cl->volumename);
    xmit[2] = cl->in;
    xmit[3] = cl->out;
    xmit[4] = cl->speed;
  }
  hosttonetcom (xmit, snd, 5);
  full_write (s->fd, snd, 5*sizeof (int));
}

send_switch (s,sw)
     Server *s;
     Swtch *sw;
{
  int xmit[5], snd[5];
  Clip *cl;

  if (sw == NULL) {
    xmit[0] = xmit[1] = xmit[2] = xmit[3] = END_OF_TRANSMISSION;
  } else {
    xmit[0] = sw->frame;
    xmit[1] = GetClipNo(sw->in);
    xmit[2] = GetClipNo(sw->out);
    xmit[3] = sw->mask;
  }
  hosttonetcom (xmit, snd, 4);
  full_write (s->fd, snd, 4*sizeof (int));
}

SeamlessPlayList(msgsock, list)
     Server *msgsock;
     List *list;
{
  G_INT32 thismajor;
  if (protomaj == -1 && msgsock->ex4 > 24) {
    protomaj = GExtensionMajor(msgsock, "Seamless editing");
    if (protomaj == NO_EXTENSION) return NO_EXTENSION;
    thismajor = protomaj;
  }
  else thismajor = G_PlayList;
  
  if (SendCommand(msgsock->fd, thismajor,list->key,
		  0,0,0,0,0,0,0,G_PlayList) == -1)
    return(_handleerror(msgsock,GIO_ERROR));
  return(NO_ERROR);
}


GFreeList(msgsock,key)
     Server *msgsock;
{
  G_INT32 thismajor;

  if (protomaj == -1 && msgsock->ex4 > 24) {
    protomaj = GExtensionMajor(msgsock, "Seamless editing");
    if (protomaj == NO_EXTENSION) return NO_EXTENSION;
    thismajor = protomaj;
  }
  else thismajor = G_FreeList;

  if (SendCommand(msgsock->fd,thismajor,key,0,0,0,0,0,0,0,G_FreeList) 
      == -1)
    return(_handleerror(msgsock,GIO_ERROR));
  return(NO_ERROR);
}

SeamlessPrintList (list)
     List *list;

{
  Clip *c = list->clips; 
  Swtch *s = list->switches;

  printf ("Clips:\n");
  while (c != NULL) {
    print_clip (c);
    c = c->next;
  }
  printf ("Switches:\n");

  while (s != NULL) {
    print_switch (s);
    s = s->next;
  }
  printf ("done.\n");
}
				
print_switch (s)
     Swtch *s;

{
  printf ("%d:	%d\n",s->frame,s->mask);
  printf ("\t");
  if ( (int) s->in > 0) print_clip (s->in);
  else printf ("%d\n",s->in);
  printf ("\t");
  if ( (int) s->out > 0) print_clip (s->out);
  else printf ("%d\n",s->out);
}

print_clip (c)
    Clip *c;
{
  printf ("%d:	%20s	%5d %5d	%d\n",
	  c->frame,c->volumename,c->in,c->out,c->speed);
}

  
#endif /* SEAMLESS */
