// <copyright> 
//  
//  Copyright (c) 1993-1996
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        object.C
//
// Purpose:    Implementation of classes Object and ObjectID
//
// Created:    16 Jul 92    Keith Andrews, IICM
//
// Modified:    1 Sep 92    Gerald Pani, IICM
// Modified:   14 Sep 94    Gerald Pani, IICM
//		     o ObjIdArray
// Modified:    9 May 95    Gerald Pani, IICM
//			o Bug fixed: implementation of Object::field[s]
//
// Description: 
// 
// 
// </file> 

#include "object.h"

#include <stdio.h>
#include <hyperg/utils/environ.h>

//Arraysimplement(RStringArray,RString)
Arraysimplement(ObjIdArray,ObjectID)
Fieldsimplement(ObjIdField,ObjectID)

//
// class ObjectID
//

static HG_UL32 readString( const char* str) {
   register HG_UL32 a = 0;
   if (!str)
      // nil pointer
      return a;
   if (str[0] != '0' || str[1] != 'x')
      return a;
   register int i = 2;
   for (; i < 10; i++) {
      if (str[i] >= '0' && str[i] <= '9') {
	 a <<= 4;
	 a += str[i] - '0';
      }
      else if (str[i] >= 'a' && str[i] <= 'f') {
	 a <<= 4;
	 a += 10 + str[i] - 'a';
      }
      else if (str[i] >= 'A' && str[i] <= 'F') {
	 a <<= 4;
	 a += 10 + str[i] - 'A';
      }
      else if (!str[i])
	 // end of string
	 break;
      else
	 // other character
	 return a;
   }
   return a;
}

ObjectID::ObjectID( const char* str ) {
   id_ = readString( str);
}

ObjectID::ObjectID( const RString& s ) {
   id_ = readString( s.string());
}

ObjectID& ObjectID::operator =( const char* s ) {
   id_ = readString( s);
   return *this;
}

ObjectID& ObjectID::operator =( const RString& s ) {
   id_ = readString( s.string());
   return *this;
}

RString ObjectID::IDString() const {
     static char* hexChars = "0123456789abcdef";
     static char buf[11];
     buf[0] = '0';
     buf[1] = 'x';

     HG_UL32 a = id_;
     for (int i = 9; i > 1; i--) {
	  buf[i] = hexChars[a & 0xf];
	  a >>= 4;
     }
     buf[10] = 0;
     return RString( buf, 10);
}

istream& operator >> ( istream& s, ObjectID &id )
{
  s.setf(0,ios::basefield) ;
  return s >> id.id_ ;
  // return s >> resetiosflags(ios::basefield) >> id.id_ ;
}

ostream& operator << ( ostream& s, const ObjectID &id )
{
     char buf[10];
     register char *buf_ptr = buf+10; // End of buf.
     
     // Now do the actual conversion, placing the result at the *end* of buf.
     // Note that we use separate code for decimal, octal, and hex,
     // so we can divide by optimizable constants.
     char *xdigs = "0123456789abcdef";
     register HG_UL32 val = id.id_;
     do {
	  *--buf_ptr = xdigs[val & 15];
	  val = val >> 4;
     } while (val != 0);
     
     while (buf_ptr > buf +2)
	  *--buf_ptr = '0';
     buf[0] = '0';
     buf[1] = 'x';
     
     s.write( buf, 10);
     return s;
}


// 
// class Object
//
boolean Object::ID( ObjectID& i ) const
{
  int tindex = indexa( rsObjectIDEq ) ;
  if ( tindex != -1 ) {
    RString tmp = gSubstrDelim( tindex, '\n');
    ObjectID onlyForGnu_HaHaHa( tmp);
    i = onlyForGnu_HaHaHa;
    return true ;
  }
  i = (HG_UL32)0;
  return false ;
}

boolean Object::GOid( ObjectID& sid, ObjectID& oid ) const
{
    RString tmp;
    if(field(rsGOidEq, tmp))
    {
        int i = 0 ;
        RString id1 ;
        RString id2 ;
        if (! tmp.gWord (i, " ", id1))
            return false ;
        i += 1;
        if (! tmp.gWord (i, "\n", id2))
            return false ;
        
        ObjectID gnu1 (id1) ;
        ObjectID gnu2 (id2) ;
        
        sid = gnu1 ;
        oid = gnu2 ;
        
        return true ;
    }
    sid = (HG_UL32)0;
    oid = (HG_UL32)0;
    return false ;
}

int Object::fields(const RString& fieldEq, RStringArray& values) const {
     int ndx = 0;
     int len = fieldEq.length();
     for(ndx = indexa(fieldEq); 
	 ndx != -1; 
	 ndx = indexa( ndx, fieldEq)
	 ) {
	  if (ndx == len || operator[](ndx - len - 1) == '\n')
	       values.insert( gSubstrDelim( ndx, '\n'));
	  int end = index(ndx, '\n');
	  if (end != -1)
	       ndx = end + 1;
	  else 
	       break;
     }
     return values.count();
}

boolean Object::field( const RString& fieldEq, RString& value) const {
     int ndx = 0;
     int len = fieldEq.length();
     for(ndx = indexa(fieldEq); 
	 ndx != -1; 
	 ndx = indexa( ndx, fieldEq)
	 ) {
	  if (ndx == len || operator[](ndx - len - 1) == '\n') {
	       value = gSubstrDelim( ndx, '\n');
	       return true;
	  }
	  int end = index(ndx, '\n');
	  if (end != -1)
	       ndx = end + 1;
	  else 
	       break;
     }
     return false;
}

void Object::convertTimesToGMT()
{
  int ndx=0;
  RString tempobj;
  RString line;
  RString name;
  RString value;
  RString timeStrings="TimeCreatedTimeModifiedTimeExpireTimeOpen";
  while (gWordChar(ndx, '\n', line))
  {
    int i;
    if ((i = line.index('=')) != -1) {
      name = line.gSubstrIndex(0, i-1);
      if (tempobj.length())
        tempobj+="\n";
      if (timeStrings.indexa(name) != -1)  // time fild found
      {
        value = Environ::lDate2gmDate(line.gRight(i+1));
        tempobj+=name+"="+value;
      }
      else
      {
        tempobj+=line;
      }
    }
  }
  operator = (tempobj);
}

void Object::convertTimesToLocalTime()
{
  int ndx=0;
  RString tempobj;
  RString line;
  RString name;
  RString value;
  RString timeStrings="TimeCreatedTimeModifiedTimeExpireTimeOpen";
  while (gWordChar(ndx, '\n', line))
  {
    int i;
    if ((i = line.index('=')) != -1) {
      name = line.gSubstrIndex(0, i-1);
      if (tempobj.length())
        tempobj+="\n";
      if (timeStrings.indexa(name) != -1)  // time fild found
      {
        value = Environ::gmDate2lDate(line.gRight(i+1));
        tempobj+=name+"="+value;
      }
      else
      {
        tempobj+=line;
      }
    }
  }
  operator = (tempobj);
}


boolean DbObject::GetField(int& ndx, RString& name, RString& value) const {
     RString line;
     if (gWordChar(ndx, '\n', line)) {
	  int i;
	  if ((i = line.index('=')) != -1) {
	       name = line.gSubstrIndex(0, i-1);
	       value = line.gRight(i+1);
	       return true;
	  }
     }
     return false;
}

