/* ----------------------------------------------------------------------------

nlmdl: status.cc

nlmdl is a C++ implementation of the statistical methods in A. Ronald 
Gallant, "Nonlinear Statistical Models," New York: John Wiley and Sons, 
1987, ISBN 0-471-80260-3, using a matrix class realmat that is distributed 
with it.  The header files nlmdl.h and realmat.h describe the use of the 
program and matrix class, respectively.  

Copyright (C) 1990, 1991, 1993, 1994, 2002.

A. Ronald Gallant
Post Office Box 659
Chapel Hill NC 27514-0659 
USA   

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, provided 
that the above copyright notice appears in all copies and that both that 
copyright notice and this permission notice appear in supporting 
documentation.  

This software is provided "as is" without any expressed or implied warranty.

---------------------------------------------------------------------------- */
/* status is a class used by nlmdl */

#include "status.h"

REAL const zero = (REAL) 0.0;

status::status()
{
  switches[0]='\0';
  method[0]='\0';
  n=0;
  M=0;
  K=0;
  p=0;
  itheta=0;
  ivar=0;
  vartype[0]='\0';
  MA=0;
  weights[0]='\0';
  tol=0;
  eps=0;
  detail[0]='\0';
  rank=0;
  df[0]='\0';
  obj=0;
  starting=STARTING_FILENAME;
  ending=ENDING_FILENAME;
}

status::~status() { }


int status::from(char* filename)
{

  ifstream ifrom(filename);
  if ( !ifrom ) {
    cerr << "Error, status::from, Cannot open " << filename << "\n";
    exit(1);
  } 

  char     junk[MAX_STATUS_LINE];
  char     newline;
  INTEGER  i,len;
  double   x = 0;
  
  if (!ifrom.get(switches,MAX_STATUS_LINE,'\n')) {
    cerr << "Error, status::from, Bad data (switches) in " << filename << "\n";
    exit(1);
  }

  if (!(ifrom>>method)) return 0;
  if ( strcmp(method,"SUR") != 0 
      && strcmp(method,"TSLS") != 0 
      && strcmp(method,"GMM") != 0 ) {
    cerr << "Error, status::from, Bad data (method) in " << filename << "\n";
    exit(1);
  }
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>n)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>M)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>K)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>p)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>itheta)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>ivar)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>vartype)) return 0;
  if ( strcmp(vartype,"homoskedastic") != 0 
       && strcmp(vartype,"heteroskedastic") != 0 ) {
    cerr << "Error, status::from, Bad data (vartype) in " << filename << "\n";
    exit(1);
  }
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>MA)) return 0;
  if ( MA<0 || MA>=n ) {
    cerr << "Error, status::from, Bad data (MA) in " << filename << "\n";
    exit(1);
  }
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>weights)) return 0;
  if ( strcmp(weights,"none") != 0 && strcmp(weights,"Parzen") != 0 ) {
    cerr << "Error, status::from, Bad data (weights) in " << filename << "\n";
    exit(1);
  }
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>x)) 
    return 0;  
  else 
    tol = (REAL)x;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>x)) 
    return 0;
  else
    eps = (REAL)x;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!(ifrom>>detail)) return 0;
  if ( strcmp(detail,"none") != 0 
       && strcmp(detail,"minimal") != 0 
       && strcmp(detail,"full") != 0 ) {
    cerr << "Error, status::from, Bad data (detail) in " << filename << "\n";
    exit(1);
  }
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;

  if (!ifrom.get(newline)) return 0;

  for (i=1; i<=5; i++) {
    if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) return 0;
    if (!ifrom.get(newline)) return 0;
  }

  if (!(ifrom>>x)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) {
    cerr << "Error, status::from, Bad data (theta) in " << filename << "\n";
    exit(1);
  }

  theta.resize(p,(INTEGER)1,zero);
  theta[1] = (REAL)x;
  
  if (p==1) return 0;
  for (i=2; i<=p; i++) {
    if(!(ifrom>>x)) {
      cerr << "Error, status::from, Bad data (theta) in " << filename << "\n";
      exit(1);
    }
    else {
     theta[i] = (REAL)x;
    }
    if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) {
      cerr << "Error, status::from, Bad data (theta) in " << filename << "\n";
      exit(1);
    }
  }

  if (!ifrom.get(newline)) return 0;

  if (!(ifrom>>x)) return 0;
  if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) {
    cerr << "Error, status::from, Bad data (var) in " << filename << "\n";
    exit(1);
  }
  
  if ( strcmp(method,"SUR") == 0 || strcmp(method,"TSLS") == 0) {
    var.resize(M,M);
    var[1] = (REAL)x;
    if (M==1) return 0;
    for (i=2; i<=M*M; i++) {
      if(!(ifrom>>x)) {
        cerr << "Error, status::from, Bad data (var) in " << filename << "\n";
        exit(1);
      }
      else {
        var[i] = (REAL)x;
      }
      if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) {
        cerr << "Error, status::from, Bad data (var) in " << filename << "\n";
        exit(1);
      }
    }
  }
  else if ( strcmp(method,"GMM") == 0 ) {
    len = M*K;
    var.resize(len,len);
    var[1] = (REAL)x;
    if (len==1) return 0;
    for (i=2; i<=len*len; i++) {
      if(!(ifrom>>x)) {
        cerr << "Error, status::from, Bad data (var) in " << filename << "\n";
        exit(1);
      }
      else {
        var[i] = (REAL)x;
      }
      if (!ifrom.get(junk,MAX_STATUS_LINE,'\n')) {
        cerr << "Error, status::from, Bad data (var) in " << filename << "\n";
        exit(1);
      }
    }
  }
  else {
    cerr << "Error, status::from, Bad data (var) in " << filename << "\n";
    exit(1);
  }

  ifrom.close();
  return 0;

}

int status::to(char* filename)
{

  ofstream oto(filename);
  if ( !oto ) {
    cerr << "Error, status::to, Cannot open " << filename << "\n";
    exit(1);
  } 

  INTEGER i,j,len;
  char    temp[MAX_STATUS_LINE];

  if (strlen(switches) == 0) {
    if (!(oto << "\tThis line is passed to class model as a string.\n")) {
      cerr << "Error, status::to, Error writing to " << filename << "\n";
      exit(1);
    }
  }
  else {
    if (!(oto << switches << "\n")) {
      cerr << "Error, status::to, Error writing to " << filename << "\n";
      exit(1);
    }
  }

  sprintf(temp,"%-19s", method);
  if (!(oto<<temp<< "What estimation method?  Code SUR, TSLS, or GMM.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d", n);
  if (!(oto<<temp<< "Number of observations, t = 1, ..., n.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d",M);
  if (!(oto<<temp<<"Number of equations, i.e. dimension of e.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d",K);
  if (!(oto<<temp<<"Number of instruments, i.e. dimension of Z.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d",p);
  if (!(oto<<temp<< "Number of parameters, i.e. dimension of theta.\n")){
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d",itheta);
  if (!(oto<<temp<< "Upper limit on Gauss-Newton iterations.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d",ivar);
  if (!(oto<<temp<< "Number var iterates, ivar=0 means none.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19s",vartype);
  if (!(oto<<temp<< "Code homoskedastic or heteroskedastic.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }
  sprintf(temp,"%-19d",MA);
  if (!(oto<<temp<< "Number of moving average terms MA for var estimate.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19s",weights);
  if (!(oto<<temp<<"Code none or Parzen, none when MA>0 is unwise.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19.6e",tol);
  if (!(oto<<temp<< "Convergence tolerance, tol=1.0e-8 is reasonable.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19.6e",eps);
  if (!(oto<<temp<< "Inversion tolerance, eps=1.0e-13 is reasonable\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);                   
  }

  sprintf(temp,"%-19s",detail);
  if (!(oto<<temp<<"How much output?  Code none, minimal, or full.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19d",rank);
  if (!(oto<<temp<< "Computed rank of V.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  sprintf(temp,"%-19s",df);
  if (!(oto<<temp<< "Divisor of var, corrected or uncorrected.\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  for (i=3; i<=5; i++) {
    if (!(oto << "                   Blank line.\n")) {
      cerr << "Error, status::to, Error writing to " << filename << "\n";
      exit(1);
    }
  }

  if ( rows(theta) <= 0 || cols(theta) <= 0 ){
    cerr << "Error, status::to, theta is not initialized.\n";
    exit(1);
  }

  for (i=1; i<=p; i++) {
    sprintf(temp,"%25.16e % 20.8f ",theta[i],theta[i]);
    if(!(oto<<temp<< " theta(" << i << ")\n")) {
      cerr << "Error, status::to, Error writing to " << filename << "\n";
      exit(1);
    }
  }

  if ( rows(var) <= 0 || cols(var) <= 0 ){
    cerr << "Warning, status::to, var is not initialized, " << filename
         << " incomplete.\n";
    return 0;
  }

  if ( strcmp(method,"SUR") == 0 || strcmp(method,"TSLS") == 0) {
    for (j=1; j<=M; j++) { 
    for (i=1; i<=M; i++) { 
      sprintf(temp,"%25.16e % 20.8f ",var.check(i,j),var(i,j));
      if(!(oto<<temp<< " var(" << i << "," << j << ")\n")) {
        cerr << "Error, status::to, Error writing to " << filename << "\n";
        exit(1);
      }
    }
    }  
  }
  else {
    len = M*K;
    for (j=1; j<=len; j++) {
    for (i=1; i<=len; i++) {
      sprintf(temp,"%25.16e % 20.8f ",var.check(i,j),var(i,j));
      if(!(oto<<temp<< " var(" << i << "," << j << ")\n")) {
        cerr << "Error, status::to, Error writing to " << filename << "\n";
        exit(1);
      }
    }
    }
  }

  if ( rows(V) <= 0 || cols(V) <= 0 ){
    cerr << "Warning, status::to, V is not initialized, file incomplete.\n";
    return 0;
  }

  for (j=1; j<=p; j++) {
  for (i=1; i<=p; i++) {
    sprintf(temp,"%25.16e % 20.8f ",V.check(i,j),V(i,j));
    if(!(oto<<temp<< " V(" << i << "," << j << ")\n" )) {
      cerr << "Error, status::to, Error writing to " << filename << "\n";
      exit(1);
    }
  }
  }


  if ( rows(D) <= 0 || cols(D) <= 0 ){
    cerr << "Error, status::to, D is not initialized.\n";
    exit(1);
  }

  for (i=1; i<=p; i++) {
    sprintf(temp,"%25.16e % 20.8f ",D[i],D[i]);
    if(!(oto<<temp<< " D(" << i << ")\n")) {
      cerr << "Error, status::to, Error writing to " << filename << "\n";
      exit(1);
    }
  }


  sprintf(temp,"%25.16e % 20.8f ",obj,obj);
  if (!(oto<<temp<< " obj\n")) {
    cerr << "Error, status::to, Error writing to " << filename << "\n";
    exit(1);
  }

  oto.close();
  return 0;

}
