/***************************************************************

Description:
  This is a a taylored linked list system for holding noncontent editor data. 
   Nodes are sorted by owner, then index. they are sorted at creation time.

Methods:
  -- shared methods --
  int    Set   (owner, index, position, type);  
  tag  * Get   (owner, index, tag *);
  int    Delete(owner, index);
  int    Delete(owner);


  -- internal methods --


 Dont use tab characters in this code.
  Dont use tab characters in this code.
   Dont use tab characters in this code.
    Dont use tab characters in this code.
     Dont use tab characters in this code.
      Dont use tab characters in this code.
       Dont use tab characters in this code.
        Dont use tab characters in this code.
         Dont use tab characters in this code.
          thanks.

History: 
 Creation Dan, <Jul 8 2002>
 

***************************************************************/

#include <stdlib.h>
#include <string.h>
#include "cestypes.h" 
#include "propaccum.h" // class definition

#include "stdio.h"  //printf

/*
typedef struct CESFieldTag {
  int64_t  Position;// first character effected 
  long     Owner   ;// unique within scope of editor 
  long     Index   ;// uniquie within scope of owner
  char     Type    ;// reference for forign translation
} CESFIELDTAG;

typedef struct FTNode{   
      CESFIELDTAG     contents;
      struct FTNode * next;
} FTNODE;

*/

PropAccum::PropAccum() {
  // initialize the linked list.
  propList = NULL;
}

PropAccum::~PropAccum() {
   deleteAll();
}

/*************************************************
*
* FREE THE NODES. FREE ALL THE NODES. FREE THEM NOW .
*
**************************************************/
void PropAccum::deleteAll() {

  CES_FIELD_TAG * cursor;

  for (; propList != NULL; cursor = propList->next) {
    free(propList);
    propList = cursor;
  } 
}


/*****************************************
*
* Description:
*  Set the attributes of a node, create 
*   it if nescissary.
*
* In:
*  Owner:    level 1 identity. e.g. the 
*    client identity.
*  Index:    level 2 identity. e.g. the 
*    bookmark number of the client.
*  Position: The character offset of this
*    tag. the purpose for its existance.
*  Type:     Used when interperting tags
*             to know what it is e.g.
*             cursor or bookmark.
*
* Out:
*  1 = success
*  0 = failure
*
*****************************************/
int PropAccum::Set(int64_t Owner, int64_t Index, int64_t Position, int Type) {

  CES_FIELD_TAG * node;

  // lookup tag
  node = FindNode(Owner, Index);
  // if the tag dosn't exist
  if (node == NULL) {
    // create tag
    if (insert(Owner, Index, Position, Type)) {  // if the tag exists
    // set attributes
    modify(node, Position, Type);
    }
  }  
  return 1;
}

/****************************************
*
* Find a node with the given owner and index.
*  This assumes that the list is sorted by
*  Owner first and then Index.
*
* IN:
*   Owner: find a tag with a matching owner and
*   Index: find a tag with a matching index
*
* OUT:
*   Success: Pointer to tag
*   Failure: NULL   
*
****************************************/
CES_FIELD_TAG * PropAccum::FindNode(int64_t Owner, int64_t Index) {

  CES_FIELD_TAG * cursor;

  for (cursor = propList; cursor != NULL; cursor = cursor->next) {
  
     // choke it up if it matches.
     if ((cursor->Owner == Owner) & (cursor->Index == Index)) {
       return cursor;
     }
     
     // give up if we passed where it should be
     if (((cursor->Owner = Owner) & (cursor->Index > Index)) |
         (cursor->Owner > Owner)
        ) {
       return NULL;
     }
  }  
  
  return NULL;
  
}


/*****************************************************
 *
 * Insert a data set into the linked list.
 * The list should be sorted first by Owner and then
 *  by Index.
 *
 * IN:
 *  Owner:    Main identity number
 *  Index:    Sub identity number
 *  Position: Value to set position to
 *  Type:     Tag type to set 
 *
 * OUT:
 *  1 = success
 *  0 = failure
 *
 ****************************************************/
int PropAccum::insert(int64_t Owner, int64_t Index, int64_t Position, int Type) {
     
  CES_FIELD_TAG * cursor;
  CES_FIELD_TAG * precursor;
  CES_FIELD_TAG * temp;

  // build a temp tag
  if ((temp = (CES_FIELD_TAG *)malloc(sizeof(CES_FIELD_TAG))) == NULL) {
    return 0;  // OUTA MEMORY
  }

  temp->Owner    = Owner;
  temp->Index    = Index;
  temp->Position = Position;
  temp->Type     = Type; 

  precursor      = propList;
  
  for (cursor = propList; cursor != NULL; cursor = cursor->next) {
    
    // choke if it matches, why were we called?
    if ((cursor->Owner == Owner) & (cursor->Index == Index)) {
      return 0;
    }
    
    // insert when we find where it should be
    if (((cursor->Owner = Owner) & (cursor->Index > Index)) |
	(cursor->Owner > Owner)
        ) {

      //precursor is now where we want this data      
      
      temp->next      = precursor->next;
      precursor->next = temp;
      return 1;
      
    }

    precursor = cursor;

  }  
  
  printf("PropAccum::insert I fell though a hole in the floor...\n");
  return 0; // how did we fall through?
}


//    modify(node, Position, Type);
/************************************************
 *
 * Modify the data of a node.
 * Why is this a method instead of just doing it?
 *  ... I dont know...
 *
 * IN:
 *  node:      Pointer to the node to modify
 *  Position:  The new value for the Position
 *  Type:      The new value fot the Type
 *
 * OUT:
 *  void
 *
 *
 ***********************************************/
void PropAccum::modify(CES_FIELD_TAG * node, int64_t Position, int64_t Type) {
  
  node->Position = Position;
  node->Type     = Type;

  // whoo! that was a tuffie!, hope I didn't make any ERRorS!

  return;
}


/*
* Direct Method
*/
int PropAccum::Set(CES_FIELD_TAG * Data) {
  
  // !!!???!!! Write me!
  printf("PropAccum::Set(CES_FIELD_TAG *) was called, but hasn't been written yet.\n");
  
  return 1;
}

/*****************************************
*
* Description:
*  Get a tag.
*
* In:
*  Owner:    level 1 identity. e.g. the 
*    client identity.
*  Index:    level 2 identity. e.g. the 
*    bookmark number of the client.
*  Dest:     pointer to a tag to put the
*    result in.
*
* Out:
*  Success: Same as Dest.
*  Failure: NULL
*
*****************************************/
CES_FIELD_TAG * PropAccum::Get(int64_t Owner, int64_t Index, CES_FIELD_TAG * Dest) {

  CES_FIELD_TAG * node;
  
  // find it.
  node = FindNode(Owner, Index);
  
  // if the tag exists
  if (node != NULL) {
    // set tag
    Dest->Position = node->Position;
    Dest->Owner    = node->Owner;
    Dest->Index    = node->Index;
    Dest->Type     = node->Type;
    return Dest;
  } 
  
  return NULL;
}








