/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
# include "attribut.h"
static char rcsid[] = "$Id: attribut.cpp 5.3 2000/05/16 13:08:04 picoSoft Exp Marco $";
static char rcsidh[] = attribut_h;
# include "dberror.h"
# include "cfield.h"
# include "relation.h" 
# include "database.h"
# include "perror.h"
# include "piteratr.h"
extern "C" {
# include <string.h>
}

static int NumDataLen[9][2] = {
   { 0, 0 },
   { 0, 0 },
   { 4, 4 },
   { 0, 0 },
   { 9, 9 },
   { 0, 0 },
   { 0, 0 },
   { 0, 0 },
   { 18, 18 }
};

PCLASSID(Attribute)

Attribute::Attribute (const PString &s, Relation * p, AttrVis vis) :
Parent(p)
{
   Visibility = vis;
   setName (s.gets());
/*//sj   
   if (p == 0) {
      PError::InternalError ("Relation == 0?");
      Temporary = PTrue;
   } else
      Temporary= PFalse;
   //sj Buffer = (char *) 0;
   Parent = p;
*/
// Inizializzazioni di default
   Order = 0;
   FldPos = 0;
   FldType = T_UNKNOWN;
   FldSize = 0;
   FldLen = 0;
   Decimal = 0;
   Sign = UNSIGNED;
   Signature = (void *) this;
   DateFmt = 0;
   serial = PFalse;
}

Attribute::Attribute (const Token &t)
{
   //sj double temp;

   PString h;
   Name = t.word;

// Inizializzazioni di default
   Order = 0;
   FldPos = 0;
   Parent = 0;
   Decimal = 0;
   Sign = UNSIGNED;
   Signature = (void *) this;
   DateFmt = 0;
   Visibility = ATTR_ALL;
   serial = PFalse;
//sj   Temporary= PTrue;
   
   switch (t.token) {
   case TIMESTAMP:
      FldType = T_CSTRING;
      setDateFmt (TIMEST_INTFMT);
      FldLen =  strlen(TIMEST_INTFMT);
      FldSize = FldLen + 1;
      break;
   case STR_LITERAL:
      FldType = T_CSTRING;
      FldLen =  (short) (t.word.size() - 2);
      FldSize = (short) (t.word.size() - 1);
      Name = t.word(1, FldLen);
      //sj Buffer = new char[FldSize];
      //sj strcpy (Buffer, t.word (1, FldLen).gets());
      break;
   case NUMBER:
      FldType = T_DOUBLE;
      FldLen = 0;
      FldSize = sizeof (double);
      //sj Buffer = (char *)new double;
      //sj temp = t.word.ToDouble();
      //sj *((double *) Buffer) = temp;
      break;
   case NULL_:
      FldType = T_UNKNOWN;
      FldLen = SQL_NULL_DATA;
      FldSize = SQL_NULL_DATA;
      //sj Buffer = (char *) 0;
      break;
   case '?':
      FldType = T_UNKNOWN;
      FldLen = 0;
      FldSize = 0;
      //sj Buffer = (char *) 0;
      break;
   }
}

Attribute::Attribute (Attribute &a)
{
   IndexPart *ip;
   
   Name =        a.Name;
   Order =       a.Order;
   FldPos =      a.FldPos;
   FldType =     a.FldType;
   FldSize =     a.FldSize;
   FldLen =      a.FldLen;
   Decimal =     a.Decimal;
   Sign =        a.Sign;
   
   for (ip = Indexes.GetFirst (); ip != 0; ip = Indexes.DeleteCurrent ())
      ;
   for (ip = a.Indexes.GetFirst (); ip != 0; ip = a.Indexes.GetNext ())
      AddIndex (*ip);
      
   Parent =      a.Parent;

/*//sj   
   if (temp == PFalse)
      Temporary =   a.Temporary;
   else
      Temporary =   temp;
   if (Temporary) {
      Buffer = new char[FldSize];
      if (a.Buffer != (char *)0)
         memcpy (Buffer, a.Buffer, (int)FldSize);
   } else {
      Buffer = a.Buffer;
   }
*/   
   Signature = a.Signature;
   DateFmt = 0;
   setDateFmt (a.DateFmt);
   Visibility = a.Visibility;
   serial = a.serial;
}

Attribute::~Attribute ()
{                
   //sj deleteBuffer();
   if (DateFmt)
      delete DateFmt;
}

void 
Attribute::setDateFmt(const char *d)
{
   if (DateFmt)
      delete DateFmt;
   DateFmt = 0;
   if (d) {
      DateFmt = new char[strlen(d) + 1];
      strcpy(DateFmt, d);
   }
}

class IndexPartIterator : public PIterator
{
public:
   IndexPartIterator (PList &l) : PIterator (&l) { }
   IndexPartIterator (PList *l) : PIterator (l)  { }
   IndexPart * operator *() { return (IndexPart *) PIterator::operator*(); }
   IndexPart ** operator++(){ return (IndexPart ** )PIterator::operator++();}
   IndexPart ** operator--(){ return (IndexPart ** )PIterator::operator--();}
   IndexPart ** operator++(int){return (IndexPart ** )PIterator::operator++(0);}
   IndexPart ** operator--(int){return (IndexPart ** )PIterator::operator--(0);}
};

PBool
Attribute::IsIndexNumber (short number)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getNumber () == number)
         return PTrue;
   return PFalse;
}

PBool
Attribute::IsIndexDups (short number)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getNumber () == number)
         return (*ip)->isDups();
   return PFalse;
}

PBool
Attribute::IsIndexPart (short part)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getPart () == part)
         return PTrue;
   return PFalse;
}

PBool
Attribute::IsIndex (short number, short part)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getNumber () == number &&
          (*ip)->getPart () == part)
         return PTrue;
   return PFalse;
}

short
Attribute::GetIndexPart (short num)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getNumber () == num)
         return (*ip)->getPart();
   return 0;
}

short
Attribute::GetIndexNum (short part)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getPart() == part)
         return (*ip)->getNumber ();
   return 0;
}

IndexPart *
Attribute::GetIndex (short num)
{
   IndexPartIterator ip(Indexes);
   
   for (ip.reset(); *ip != 0; ip++)
      if ((*ip)->getNumber () == num)
         return *ip;
   return 0;
}

void
Attribute::setType (DataType t, long i, int d, PBool ser)
{
   FldType = t;
   FldLen = i;
   Decimal = d;

   switch (FldType) {
   case T_CSTRING:
      FldSize = FldLen;
      break;
   case T_BLOB:
   case T_CLOB:
      FldLen = 11;
      FldSize = FldLen / 2 + 1;
      break;
   case T_PACKED_ORDERED:
      FldSize = FldLen / 2 + 1;
      break;
   case T_SHORT:
      FldSize = 2;
      break;
   case T_LONG:
   case T_FLOAT:
      FldSize = 4;
      break;
   case T_DOUBLE:
      FldSize = 8;
      break;
   case T_UNKNOWN:
      FldSize = 0;
      break;
   default:
      PError::InternalError ("Invalid type in setType");
      break;
   }
   serial = ser;
}

PString
Attribute::getCreateDesc ()
{
   PString Return;

   switch (FldType) {
   case T_CSTRING:
      Return.prints ("CHAR (%d)", FldSize);
      break;
   case T_BLOB:
      Return = "BLOB";
      break;
   case T_CLOB:
      Return = "CLOB";
      break;
   case T_PACKED_ORDERED:
      if (DateFmt) {
         if (strcmp (DateFmt,TIME_INTFMT) == 0)
            Return = "TIME";
         else if (strcmp (DateFmt,DATE_INTFMT) == 0)
            Return = "DATE";
         else
            Return = "TIMESTAMP";
      } else
         Return.prints ("NUMERIC (%d,%d)", FldLen, Decimal);
      break;
   case T_SHORT:
      Return = "SMALLINT";
      break;
   case T_LONG:
      Return = "INTEGER";
      break;
   case T_FLOAT:
      Return = "REAL";
      break;
   case T_DOUBLE:
      Return = "DOUBLE";
      break;
   default:
      PError::InternalError ("Invalid type in getCreateDesc");
      break;
   }
   return Return;
}



