/***************************************************************************
                          ifmt.cpp  -  formatted input
                             -------------------
    begin                : July 22 2002
    copyright            : (C) 2002 by Marc Schellens
    email                : m_schellens@users.sf.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "datatypes.hpp"
#include "dstructgdl.hpp"
#include "real2int.hpp"
#include "calendar.hpp"


// needed with gcc-3.3.2
#include <cassert>
#include <iostream>
#include <sstream>
#include <iomanip>

using namespace std;

// on input all format codes are the similar
// only the default width is important
// (dec, hex, oct are also supported)

void ReadNext( istream& is, string& buf)
{
  bool trail = false;
  char c;
  for(;;)
    {
      c = is.get();

      //      int cc = c;
      //      cout << "c: " << cc << " ("<<c<<")"<<endl;
      
      if( is.eof())  return;
      if( c == '\n') return;
      if( trail && (c == ' ' || c == '\t'))
	{
	  is.unget();
	  return;
	}

      buf.push_back( c);
      trail = true;
    }
}

// read double
inline double ReadD( istream* is, int w)
{
  if( w > 0)
    {
      char *buf = new char[ w+1];
      ArrayGuard<char> guard( buf);
      is->get( buf, w+1); 
      return Str2D( buf);
   }
  else if( w == 0)
    {
      string buf;
      ReadNext( *is, buf);
      return Str2D( buf.c_str());
    }
  else
    {
      string buf;
      getline( *is, buf);
      return Str2D( buf.c_str());
    }
}
// read long
inline long int ReadL( istream* is, int w, int base=10)
{
  if( w > 0)
    {
      char *buf = new char[ w+1];
      ArrayGuard<char> guard( buf);
      is->get( buf, w+1); 
      return Str2L( buf, base);
   }
  else if( w == 0)
    {
      string buf;
      ReadNext( *is, buf);
      return Str2L( buf.c_str(), base);
    }
  else
    {
      string buf;
      getline( *is, buf);
      return Str2L( buf.c_str(), base);
    }
}
// read unsigned long
inline unsigned long int ReadUL( istream* is, int w, int base=10)
{
  if( w > 0)
    {
      char *buf = new char[ w+1];
      ArrayGuard<char> guard( buf);
      is->get( buf, w+1); 
      return Str2UL( buf, base);
   }
  else if( w == 0)
    {
      string buf;
      ReadNext( *is, buf);
      return Str2UL( buf.c_str(), base);
    }
  else
    {
      string buf;
      getline( *is, buf);
      return Str2UL( buf.c_str(), base);
    }
}

// A code
// string
template<> SizeT Data_<SpDString>::
IFmtA( istream* is, SizeT offs, SizeT r, int w) 
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();

  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;

  SizeT endEl = offs + tCount;

   if( w <= 0)
    for( SizeT i=offs; i<endEl; i++)
      getline( *is, (*this)[ i]);
  else
    {
      char *buf = new char[ ++w];
      ArrayGuard<char> guard( buf);
      for( SizeT i=offs; i<endEl; i++)
	{
	  is->get( buf, w);
	  (*this)[ i] = buf; //string( buf);
	  if( is->eof()) // ignore if length is too short
	    {
	      if( i == (endEl-1))
		is->clear();

	      assert( is->good());
	    }
	}
    }

  return tCount;
}
// int (long, ...)
template<> SizeT Data_<SpDInt>::
IFmtA( istream* is, SizeT offs, SizeT r, int w)
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    (*this)[ i] = ReadL( is, w);
  
  return tCount;
}
template<> SizeT Data_<SpDLong>::
IFmtA( istream* is, SizeT offs, SizeT r, int w)
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    (*this)[ i] = ReadL( is, w);
  
  return tCount;
}
template<> SizeT Data_<SpDLong64>::
IFmtA( istream* is, SizeT offs, SizeT r, int w)
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    (*this)[ i] = ReadL( is, w);
  
  return tCount;
}
// unsigned int (unsigned long, ...)
template<class Sp> SizeT Data_<Sp>::
IFmtA( istream* is, SizeT offs, SizeT r, int w)
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    (*this)[ i] = ReadUL( is, w);
  
  return tCount;
}

// float (double, ...)
template<> SizeT Data_<SpDFloat>::
IFmtA( istream* is, SizeT offs, SizeT r, int w)
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    (*this)[ i] = ReadD( is, w);
  
  return tCount;
}
template<> SizeT Data_<SpDDouble>::
IFmtA( istream* is, SizeT offs, SizeT r, int w)
{
  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    (*this)[ i] = ReadD( is, w);
  
  return tCount;
}

// complex, complexdbl (replace float with double)
template<> SizeT Data_<SpDComplex>::
IFmtA( istream* is, SizeT offs, SizeT r, int w) 
{
  float re, im;

  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();

  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;

  SizeT firstEl = offs / 2;


  if( offs & 0x01)
    {
    im = ReadD( is, w);
    (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
    firstEl++;
    tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
    re = ReadD( is, w);
    im = ReadD( is, w);
    (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
    re = ReadD( is, w);
    (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }

  return tCountIn;
}
template<> SizeT Data_<SpDComplexDbl>::
IFmtA( istream* is, SizeT offs, SizeT r, int w) 
{
  double re, im;

  if( w < 0) w = 0;

  SizeT nTrans = ToTransfer();

  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;

  SizeT firstEl = offs / 2;


  if( offs & 0x01)
    {
    im = ReadD( is, w);
    (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
    firstEl++;
    tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
    re = ReadD( is, w);
    im = ReadD( is, w);
    (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
    re = ReadD( is, w);
    (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }

  return tCountIn;
}

// I O Z formats
// string
template<> SizeT Data_<SpDString>::
IFmtI( istream* is, SizeT offs, SizeT r, int w,
       BaseGDL::IOMode oMode) 
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = i2s(ReadL( is, w, oMode),8);
    }
  
  return tCount;
}
// int (long, ...)
template<class Sp> SizeT Data_<Sp>::
IFmtI( istream* is, SizeT offs, SizeT r, int w,
       BaseGDL::IOMode oMode) 
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = ReadL( is, w, oMode);
    }
  
  return tCount;
}
// unsigned long (unsigned int can be handled by default)
template<> SizeT Data_<SpDULong>::
IFmtI( istream* is, SizeT offs, SizeT r, int w,
       BaseGDL::IOMode oMode) 
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = ReadUL( is, w, oMode);
    }
  
  return tCount;
}
// complex, complexdbl (replace float with double)
template<> SizeT Data_<SpDComplex>::
IFmtI( istream* is, SizeT offs, SizeT r, int w, 
       BaseGDL::IOMode oMode) 
{
  float re, im;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;

  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;
  
  SizeT firstEl = offs / 2;

  if( offs & 0x01)
    {
      im = ReadL( is, w, oMode);
      (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
      firstEl++;
      tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
      re = ReadL( is, w, oMode);
      im = ReadL( is, w, oMode);
      (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
      re = ReadL( is, w, oMode);
      (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }
  
  return tCountIn;
}
template<> SizeT Data_<SpDComplexDbl>::
IFmtI( istream* is, SizeT offs, SizeT r, int w, 
       BaseGDL::IOMode oMode) 
{
  double re, im;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;
  
  SizeT firstEl = offs / 2;

  if( offs & 0x01)
    {
      im = ReadL( is, w, oMode);
      (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
      firstEl++;
      tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
      re = ReadL( is, w, oMode);
      im = ReadL( is, w, oMode);
      (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
      re = ReadL( is, w, oMode);
      (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }
  
  return tCountIn;
}

// F code
// string
template<> SizeT Data_<SpDString>::
IFmtF( istream* is, SizeT offs, SizeT r, int w)
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = i2s(ReadD( is, w),8);
    }
  
  return tCount;
}
// int
template<class Sp> SizeT Data_<Sp>::
IFmtF( istream* is, SizeT offs, SizeT r, int w)
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = Real2Int<Ty,double>(ReadD( is, w));
    }
  
  return tCount;
}
// float
template<> SizeT Data_<SpDFloat>::
IFmtF( istream* is, SizeT offs, SizeT r, int w)
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = ReadD( is, w);
    }
  
  return tCount;
}
// double
template<> SizeT Data_<SpDDouble>::
IFmtF( istream* is, SizeT offs, SizeT r, int w)
{
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  
  SizeT endEl = offs + tCount;
  
  for( SizeT i=offs; i<endEl; i++)
    {
      (*this)[ i] = ReadD( is, w);
    }
  
  return tCount;
}
// complex, complexdbl (replace float with double)
template<> SizeT Data_<SpDComplex>::
IFmtF( istream* is, SizeT offs, SizeT r, int w) 
{
  float re, im;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;
  
  SizeT firstEl = offs / 2;
  
  if( offs & 0x01)
    {
      im = ReadD( is, w);
      (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
      firstEl++;
      tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
      re = ReadD( is, w);
      im = ReadD( is, w);
      (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
      re = ReadD( is, w);
      (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }
  
  return tCountIn;
}
template<> SizeT Data_<SpDComplexDbl>::
IFmtF( istream* is, SizeT offs, SizeT r, int w) 
{
  double re, im;

  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;
  
  SizeT firstEl = offs / 2;
  
  if( offs & 0x01)
    {
      im = ReadD( is, w);
      (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
      firstEl++;
      tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
      re = ReadD( is, w);
      im = ReadD( is, w);
      (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
      re = ReadD( is, w);
      (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }
  
  return tCountIn;
}

// struct ***************************************************
// struct just calls the appropriate functions on its tags
// common code for all struct output functions
void DStructGDL::IFmtAll( SizeT offs, SizeT r,
			  SizeT& firstIn, SizeT& firstOffs,
			  SizeT& tCount, SizeT& tCountIn)
{
  SizeT nTrans = ToTransfer();

  // transfer count
  tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  tCountIn = tCount;

  // find first Element
  SizeT oneElTr = nTrans / N_Elements();

  SizeT firstEl = offs / oneElTr;
  firstOffs =  offs % oneElTr;

  // find first tag
  SizeT nB = 0;
  SizeT nTags=NTags();
  SizeT firstTag = 0;
  for( firstTag=0; firstTag < nTags; firstTag++)
      {
	SizeT tt=GetTag( firstTag)->ToTransfer();
	nB += tt;
	if( nB > firstOffs)
	  {
	    nB -= tt;
	    break;
	  }
      }

  firstIn = firstEl * NTags() + firstTag;
  firstOffs -= nB;
}
SizeT DStructGDL::
IFmtA( istream* is, SizeT offs, SizeT r, int w) 
{
  SizeT firstIn, firstOffs, tCount, tCountIn;
  IFmtAll( offs, r, firstIn, firstOffs, tCount, tCountIn);

  SizeT trans = (*this)[ firstIn]->IFmtA( is, firstOffs, tCount, w);
  if( trans >= tCount) return tCountIn;
  tCount -= trans;

  SizeT ddSize = dd.size();
  for( SizeT i = (firstIn+1); i < ddSize; i++)
    {
      trans = (*this)[ i]->IFmtA( is, 0, tCount, w);
      if( trans >= tCount) return tCountIn;
      tCount -= trans;
    }

  return tCountIn;
}
SizeT DStructGDL::
IFmtI( istream* is, SizeT offs, SizeT r, int w,  
       BaseGDL::IOMode oMode) 
{
  SizeT firstIn, firstOffs, tCount, tCountIn;
  IFmtAll( offs, r, firstIn, firstOffs, tCount, tCountIn);

  SizeT trans = (*this)[ firstIn]->IFmtI( is, firstOffs, tCount, w, oMode);
  if( trans >= tCount) return tCountIn;
  tCount -= trans;

  SizeT ddSize = dd.size();
  for( SizeT i = (firstIn+1); i < ddSize; i++)
    {
      trans = (*this)[ i]->IFmtI( is, 0, tCount, w, oMode);
      if( trans >= tCount) return tCountIn;
      tCount -= trans;
    }
  
  return tCountIn;
}
SizeT DStructGDL::
IFmtF( istream* is, SizeT offs, SizeT r, int w) 
{
  SizeT firstIn, firstOffs, tCount, tCountIn;
  IFmtAll( offs, r, firstIn, firstOffs, tCount, tCountIn);

  SizeT trans = (*this)[ firstIn]->IFmtF( is, firstOffs, tCount, w);
  if( trans >= tCount) return tCountIn;
  tCount -= trans;

  SizeT ddSize = dd.size();
  for( SizeT i = (firstIn+1); i < ddSize; i++)
    {
      trans = (*this)[ i]->IFmtF( is, 0, tCount, w);
      if( trans >= tCount) return tCountIn;
      tCount -= trans;
    }

  return tCountIn;
}
int getPosInStringArray(string *array, int nval, string what)
{
  for (int i=0; i<nval; i++){
    if (what.compare(0,what.length(),array[i],0,what.length())==0) return i+1;
  }
  return -1;
}


   
 DDouble ReadFmtCal( string what, int w, BaseGDL::Cal_IOMode cMode)
 {
   static string theMonth[12]={"January","February","March","April","May","June",
      "July","August","September","October","November","December"};
   static string theMONTH[12]={"JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE",
      "JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"};
   static string themonth[12]={"january","february","march","april","may","june",
      "july","august","september","october","november","december"};
   static string theDAY[7]={"MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY","SUNDAY"};
   static string theDay[7]={"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
   static string theday[7]={"monday","tuesday","wednesday","thursday","friday","saturday","sunday"};
   static string capa[2]={"am","pm"};
   static string cApa[2]={"Am","Pm"};
   static string cAPa[2]={"AM","PM"};
 
  static DLong iMonth=1;
  static DLong iDay=1;
  static DLong iYear=1;
  static DLong iHour=12;
  static DLong iMinute=0;
  static DLong icap=0;
  static DDouble Second=0.0;
  static DDouble Value;
  string fmt;
  what=StrUpCase(what);
  switch ( cMode ) {
    case BaseGDL::COMPUTE:
      if (iHour < 13 && icap == 2) {//sole case icap plays a role
        iHour += 12;
      }
      if (!dateToJD(Value, iDay, iMonth, iYear, iHour, iMinute, Second)) throw GDLException("Invalid Julian date input.");
      iMonth=1; iDay=1; iYear=1; iHour=12; iMinute=0; Second=0.0; icap=0; //IDL default...
      break;
    case BaseGDL::DEFAULT:
      //IDL complains when ifDow is wrong... is it really useful?
      iMonth=getPosInStringArray(theMONTH, 12, what.substr(4,3));
      if (iMonth == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what.substr(4,3)+".");
      iDay=Str2L( what.substr(8,2).c_str(), 10);
      if (iDay < 0 || iDay > 31) throw GDLException("Unable to apply format code "+fmt+" to input: "+what.substr(8,2)+".");
      iHour=Str2L( what.substr(11,2).c_str(), 10);
      if (iHour < 0 || iHour > 23) throw GDLException("Unable to apply format code "+fmt+" to input: "+what.substr(11,2)+".");
      iMinute=Str2L( what.substr(14,2).c_str(), 10);
      if (iMinute < 0 || iMinute > 59) throw GDLException("Unable to apply format code "+fmt+" to input: "+what.substr(14,2)+".");
      Second=Str2L( what.substr(17,2).c_str(), 10); //Str2D since it is in format integer (CSI2.2)
      if (Second < 0 || Second > 59.0) throw GDLException("Unable to apply format code "+fmt+" to input: "+what.substr(17,2)+".");
      iYear=Str2L( what.substr(20,4).c_str(), 10);
      if (iYear < -4716 || iYear > 5000000 || iYear == 0) throw GDLException("Value of Julian date is out of allowed range.");
      break;
    case BaseGDL::CMOA:
      fmt="CMOA";
      iMonth=getPosInStringArray(theMONTH, 12, what);
      if (iMonth == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CMoA:
      fmt="CMoA";
      iMonth=getPosInStringArray(theMONTH, 12, what);
      if (iMonth == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CmoA:
      fmt="CmoA";
      iMonth=getPosInStringArray(theMONTH, 12, what);
      if (iMonth == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CDWA:
    case BaseGDL::CDwA:
    case BaseGDL::CdwA:
      //do nothing -- day of week is not useful.
      break;
    case BaseGDL::CapA:
      fmt="CapA";
      //icap should modify date. FIXME.
      icap=getPosInStringArray(cAPa, 2, what);
      if (icap == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CApA:
      fmt="CApA";
      //icap should modify date. FIXME.
      icap=getPosInStringArray(cAPa, 2, what);
      if (icap == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CAPA:
      fmt="CAPA";
      //icap should modify date. FIXME.
      icap=getPosInStringArray(cAPa, 2, what);
      if (icap == -1) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CMOI:
      fmt="CMOI";
      iMonth=Str2L( what.c_str(), 10);
      if (iMonth < 1 || iMonth > 12) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CYI:
      fmt="CYI";
      iYear=Str2L( what.c_str(), 10);
      if (iYear < -4716 || iYear > 5000000 || iYear == 0) throw GDLException("Value of Julian date is out of allowed range.");
      break;
    case BaseGDL::ChI:
      fmt="ChI";
      //AM-PM hour -- to be modified by CaPA.
      iHour=Str2L( what.c_str(), 10);
      if (iHour < 0 || iHour > 12) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CHI:
      fmt="CHI";
      iHour=Str2L( what.c_str(), 10);
      if (iHour < 0 || iHour > 23) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CDI:
     fmt="CDI";
      iDay=Str2L( what.c_str(), 10);
      if (iDay < 0 || iDay > 31) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CMI:
     fmt="CMI";
      iMinute=Str2L( what.c_str(), 10);
      if (iMinute < 0 || iMinute > 59) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    case BaseGDL::CSI:
      fmt="CSI";
      Second=Str2L( what.c_str(), 10);
      if (Second < 0 || Second > 59.0) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
       break;
      //Float
    case BaseGDL::CSF:
      fmt="CSF";
      Second=Str2D( what.c_str());
      if (Second < 0.0 || Second > 60.0) throw GDLException("Unable to apply format code "+fmt+" to input: "+what+".");
      break;
    default:
      std::cerr<<"unhandled switch statement, please report!"<<std::endl;
  }
  return Value;
 }

 string IFmtGetString(istream* is, int w)
 {
   string what;
  if( w > 0)
    {
      char *buf = new char[ w+1];
      ArrayGuard<char> guard( buf);
      is->get( buf, w+1);
      what.assign(buf);
   }
  else if( w == 0)
    {
      ReadNext( *is, what);
    }
  else
    {
      getline( *is, what);
    }
   return what;
 }
 
template<> SizeT Data_<SpDString>::
IFmtCal( istream* is, SizeT offs, SizeT r, int w, BaseGDL::Cal_IOMode cMode)
{
//  ***NOT COMPLETE: Repeat count will mostly *NOT* Work ! FIXME (see ofmt.cpp solution!)
  DDouble val = ReadFmtCal( IFmtGetString(is, w), w, cMode);
  std::ostringstream s;
  s << setw( 16 ) << std::scientific<< val;
  (*this)[ offs] = s.str();
  return 1;
}
template<> SizeT Data_<SpDComplex>::
IFmtCal( istream* is, SizeT offs, SizeT r, int w, BaseGDL::Cal_IOMode cMode)
{
//  ***NOT COMPLETE: Repeat count will mostly *NOT* Work ! FIXME (see ofmt.cpp solution!)
  DFloat re, im;
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;
  
  SizeT firstEl = offs / 2;
  
  if( offs & 0x01)
    {
      im = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
      firstEl++;
      tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
      re = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      im = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
      re = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }
  
  return tCountIn;
}

template<> SizeT Data_<SpDComplexDbl>::
IFmtCal( istream* is, SizeT offs, SizeT r, int w, BaseGDL::Cal_IOMode cMode)
{
//  ***NOT COMPLETE: Repeat count will mostly *NOT* Work ! FIXME (see ofmt.cpp solution!)
  DDouble re, im;
  SizeT nTrans = ToTransfer();
  
  // transfer count
  SizeT tCount = nTrans - offs;
  if( r < tCount) tCount = r;
  SizeT tCountIn = tCount;
  
  SizeT firstEl = offs / 2;
  
  if( offs & 0x01)
    {
      im = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      (*this)[ firstEl] = Ty( (*this)[ firstEl].real(), im);
      firstEl++;
      tCount--;
    }

  SizeT endEl = firstEl + tCount / 2;

  for( SizeT i= firstEl; i<endEl; i++)
    {
      re = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      im = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      (*this)[ i] = Ty( re, im);
    }

  if( tCount & 0x01)
    {
      re = ReadFmtCal( IFmtGetString(is, w), w, cMode);
      (*this)[ endEl] = Ty( re, (*this)[ endEl].imag());
    }
  
  return tCountIn;
}
template<class Sp> SizeT Data_<Sp>::
IFmtCal( istream* is, SizeT offs, SizeT r, int w, BaseGDL::Cal_IOMode cMode)
{
//  ***NOT COMPLETE: Repeat count will mostly *NOT* Work ! FIXME (see ofmt.cpp solution!)

  (*this)[ offs] = ReadFmtCal( IFmtGetString(is, w), w, cMode);
  return 1;
}
SizeT DStructGDL::
IFmtCal( istream* is, SizeT offs, SizeT r, int w, BaseGDL::Cal_IOMode cMode) 
{
//  ***NOT COMPLETE: Repeat count will mostly *NOT* Work ! FIXME (see ofmt.cpp solution!)
  SizeT firstIn, firstOffs, tCount, tCountIn;
  IFmtAll( offs, 1, firstIn, firstOffs, tCount, tCountIn);

  SizeT trans = (*this)[ firstIn]->IFmtCal( is, firstOffs, r, w, cMode);
  if( trans >= tCount) return tCountIn;
  tCount -= trans;

  SizeT ddSize = dd.size();
  for( SizeT i = (firstIn+1); i < ddSize; i++)
    {
      trans = (*this)[ i]->IFmtCal( is, 0, r, w, cMode);
      if( trans >= tCount) return tCountIn;
      tCount -= trans;
    }
  
  return tCountIn;
}


#include "instantiate_templates.hpp"

