/* This class adds to ListBox the specific capabilities of a list box that holds video records.  This includes managing a parallel list of videos as an Dictionary object, stored in the videoCollection instance variable. */!!

inherit(ListBox, #VideoList, #(videoCollection), 2, nil)!!

now(class(VideoList))!!

/* Create a new list box object in Actor and Windows.
  Parent passes itself and the control ID. */
Def new (self, id, par | theLB)
{ theLB := new(self:Behavior);
  /* create object */
  setVars(theLB, id, par);
  create(theLB, nil, "ListBox", LBS_STANDARD bitOr 
    WS_CHILD bitOr LBS_USETABSTOPS);
  if handle(theLB) = 0
  then alert(System, self, #wCreateError);
  endif;
  init(theLB);
  ^theLB;
}!!

now(VideoList)!!

/* Returns the entire collection of videos as one
  string.  Data fields are delimited by Tab characters
  and videos are delimited by CR_LF. */
Def asExportString(self | str)
{ str := "";
  assocsDo(videoCollection,
  {using(videoAssoc | videoStr) 
    videoStr := asString(key(videoAssoc)) + 
      asString(Tab);
    videoStr := videoStr + 
      asExportString(value(videoAssoc));
    str := str + videoStr + CR_LF;
  });
  ^str;
}
!!

/* Returns a collection of strings corresponding to
  the part number of each video on hand. */
Def getLabels(self | labelColl)
{ labelColl := new(OrderedCollection, 5);
  keysDo(videoCollection,
  {using(partNum) add(labelColl, asString(partNum));
  }); 
  ^labelColl;
}
!!

/* Returns a collection of numbers corresponding to
the quantity of each video on hand. */
Def getData(self | dataColl)
{ dataColl := new(OrderedCollection, 5);
  do(videoCollection,
  {using(aVideo) add(dataColl, quantityOnHand(aVideo));
  });
  ^dataColl;
}
!!

/* Returns the number of videos currently stored. */
Def size(self)
{ ^size(videoCollection);
}
!!

/* Returns a the total cost of all video items 
  requiring reordering. */
Def reorderTotal(self | subTotal, reorderColl)
{ subTotal := 0.;
  reorderColl := extract(videoCollection, {using(aVideo) 
    minimumQuantity(aVideo) > quantityOnHand(aVideo)
  });
  do(reorderColl,
  {using(aVid)
    subTotal := subTotal + reorderCost(aVid);
  });
  ^subTotal;
}
!!

/* Returns a collection of strings each representing a 
  video item requiring reordering. */
Def reorderStrings(self | reorderColl, strColl)
{ strColl := new(OrderedCollection, 4);
  reorderColl := extract(videoCollection, {using(aVideo) 
    minimumQuantity(aVideo) > quantityOnHand(aVideo)
  });
  assocsDo(reorderColl,
  {using(vAssoc)
    add(strColl, right(asString(key(vAssoc)), 5, " ") +
      " " + asReorderString(value(vAssoc)));        
  });
  ^strColl;
}
!!

/* Clears the list box and video collection of 
  items. */
Def clear(self)
{ clear(videoCollection);
  clearList(self);
} !!

/* Loads the video collection from the specified 
  file. */
Def load(self, aFile | aVideo, aPartNum)
{ redrawOff(self);
  loop
  while not(atEnd(aFile))
  begin 
    aPartNum := asInt(readLine(aFile), 10);
    aVideo := new(Video);
    load(aVideo, aFile);
    addVideo(self, aPartNum, aVideo);
    readChar(aFile); readChar(aFile);
  endLoop;
  redrawOn(self);
  invalidate(self);
}
!!

/* Reduces the quantity on hand of the currently 
  selected video by the amount specified in qty.
  This includes deleting and reinserting the video
  string in the list box. */
Def shipVideo(self, qty | theVideo, thePartNum)
{ theVideo := getSelVideo(self);
  thePartNum := getSelPartNum(self);
  ship(theVideo, qty);
  redrawOff(self);
  sendMessage(self, LB_DELETESTRING, 
    getSelIdx(self), 0L);
  addString(self, right(asString(thePartNum), 3, " ") 
    + asString(Tab) + asLBString(theVideo));
  selectString(self, right(asString(thePartNum), 3, " "));  
  redrawOn(self);
  invalidate(self);
}
!!

/* Adds a new video entry into both the list box and 
  the list of videos. */
Def addVideo(self, partNum, newVideo)
{ add(videoCollection, partNum, newVideo);
  addString(self, right(asString(partNum), 3, " ") 
    + asString(Tab) + asLBString(newVideo));
}
!!

/* Returns the part number of the video corresponding
  to the currently selected list box item, or nil if
  no item is selected. */
Def getSelPartNum(self | selText, numText)
{ if (selText := getSelString(self)) <> nil
  then 
    numText := leftJustify(subString(selText, 0, 3));
    ^asInt(numText, 10);
  else ^nil;
  endIf;
}
!!

/* Initializes the video list object by 
  initializing the videoCollection instance variable 
  and setting the list box's tab stops and font. */
Def init(self | tabStruct)
{ videoCollection := new(Dictionary, 10);
  sendMessage(self, WM_SETFONT,
    Call GetStockObject(SYSTEM_FIXED_FONT), 1L);
  tabStruct := new(Struct, 6);
  putWord(tabStruct, 25, 0);
  putWord(tabStruct, 105, 2);
  putWord(tabStruct, 135, 4);
  sendMessage(self, LB_SETTABSTOPS, 3, lP(tabStruct));
  freeHandle(tabStruct);
} !!

/* Returns the video object corresponding to the 
  currently selected list box item, or nil if
  no item is selected. */
Def getSelVideo(self | partNum)
{  if (partNum := getSelPartNum(self)) <> nil
  then ^videoCollection[partNum];
  else ^nil;
  endIf;
}
!!