#include <stdio.h>
#include <iostream>
#include <string.h>
#include <assert.h>
#include "snopt.hh"
#include "amplProblem.hh"
#include "snoptProblem.hh"
#include "asl.h"
#include "getstub.h"

using namespace std;

static ASL *asl;

int amplusrfg_( integer    *Status, integer *n,    doublereal x[],
		integer    *needF,  integer *neF,  doublereal F[],
		integer    *needG,  integer *neG,  doublereal G[],
		char       *cu,     integer *lencu,
		integer    iu[],    integer *leniu,
		doublereal ru[],    integer *lenru )
{
  fint err;
  if (*needF) {
    int nobj = 0;

    F[0] = objval( nobj, x, &err );
    if (*neF > 1){
      conval( x, F+1, &err);
    }
  }
  if(*needG) {
    objgrd( 0, x, G, &err );
    if (n_con) jacval(x, G+ (*n), &err );
  }
}


int amplusrf_( integer    *Status, integer *n,    doublereal x[],
	       integer    *needF,  integer *neF,  doublereal F[],
	       integer    *needG,  integer *neG,  doublereal G[],
	       char       *cu,     integer *lencu,
	       integer    iu[],    integer *leniu,
	       doublereal ru[],    integer *lenru )
{
  fint err;
  int nobj = 0;

   F[0] = objval( nobj, x, &err );
  if (*neF > 1){
    conval( x, F+1, &err);
  }
}

amplProblem::amplProblem( int aargc, char **aargv ) :
  argc(aargc), argv(aargv)
{
  xlow = 0;  xupp = 0;  x = 0;  xmul = 0;

  Flow = 0;  Fupp = 0;  F = 0;  Fmul = 0;

  xstate = 0;  Fstate = 0;

  iAfun  = 0; jAvar = 0; A = 0;
  iGfun  = 0; jGvar = 0;

  xnames = 0;
  Fnames = 0;

  asl = ASL_alloc( ASL_read_pfgh );

  // Pretty annoying to have to create a temp here, but it's the only
  // way I know to initialize the oi structure correctly.
  Option_Info temp_oi = { "snampl", "snampl"};
  oi = new Option_Info;
  *oi = temp_oi;
}

amplProblem::~amplProblem()
{
  if (xlow != 0 ) delete []xlow;
  if (xupp != 0 ) delete []xupp;
  if (x    != 0 ) delete []x;
  if (xmul != 0 ) delete []xmul;

  if (Flow != 0 ) delete []Flow;
  if (Fupp != 0 ) delete []Fupp;
  if (F    != 0 ) delete []F;
  if (Fmul != 0 ) delete []Fmul;

  if (xstate != 0 ) delete []xstate;
  if (Fstate != 0 ) delete []Fstate;

  if (iAfun != 0 ) delete []iAfun;
  if (jAvar != 0 ) delete []jAvar;
  if (A     != 0 ) delete []A;
  if (iGfun != 0 ) delete []iGfun;
  if (jGvar != 0 ) delete []jGvar;


  if (xnames != 0 ) delete []xnames;
  if (Fnames != 0 ) delete []Fnames;

  if (Uvx    != 0 ) delete [] Uvx;     Uvx   = 0;
  if (Urhsx  != 0 ) delete [] Urhsx;   Urhsx = 0;

  ASL_free( &asl );
  delete oi;
}

void amplProblem::alloc( integer n, integer neF)
{
  xlow = new doublereal[n];
  xupp = new doublereal[n];
  x    = new doublereal[n];
  xmul = new doublereal[n];

  Flow   = new doublereal[neF];
  Fupp   = new doublereal[neF];
  Fmul   = new doublereal[neF];
  F      = new doublereal[neF];

  xstate = new integer[n];
  Fstate = new integer[neF];

  Uvx   =  new real[n_var];
  Urhsx =  new real[n_con];
}

void amplProblem::initialize()
{
  char * stub = getstops(argv, oi);
  if (!stub) { // Couldn't find the name of the stub file
    printf("Usage: %s stub\n", argv[0]);
    ierr = 1;
  }
  FILE * nl = jac0dim( stub, (fint) strlen( stub ) );
  // Set the "U" vectors so that the ampl reader will store the
  // upper and lower bounds separately
  n     = n_var;
  neF   = n_con + 1;
  this->alloc(n,neF);
  // Initial x
  X0    =  x;

  ierr = pfgh_read( nl, 0 );

  memcpy( xlow, LUv, n_var*sizeof(doublereal));
  memcpy( xupp, Uvx, n_var*sizeof(doublereal));
  memcpy( Flow+1, LUrhs, n_con*sizeof(doublereal));
  memcpy( Fupp+1, Urhsx, n_con*sizeof(doublereal));

  this->makePrintName();

  usrfun = amplusrfg_;
  int nhnz = sphsetup(0, 0, n_con > 0, 1);

  lenG = nzc + n; //Number of nonzeros in F;

  neG  = lenG;
  lenA = lenG;
  neA  = 0;
  iGfun = new integer[lenG];
  jGvar = new integer[lenG];
  iAfun = new integer[lenA];
  jAvar = new integer[lenA];
  A     = new doublereal[lenA];

  nxnames = 1;
  nFnames = 1;
  xnames = new char[nxnames*8];
  Fnames = new char[nFnames*8];

  ObjRow = 0;
  ObjAdd = 0;

  /* Set xstate and Fstate to zero. */
  memset( xstate, 0, n*sizeof(integer) );
  memset( Fstate, 0, neF*sizeof(integer) );

  //Set for objective portion.
  memset( iGfun, 0, n*sizeof(integer));
  for( int i = 0; i < n; i++ ) jGvar[i] = i;

//   memset( iGfun, 0, nzo*sizeof(doublereal));
//   int count = 0;
//   ograd *og, **ogp = Ograd;
//   for( og = *ogp++; og; og = og->next ) {
//     jGvar[count++] = og->varno;
//   }

  //Now lets handle the rest.
  cgrad *cg, **cgp = Cgrad;
  for(int i = 1; i < n_con+1; i++)
    for(cg = *cgp++; cg; cg = cg->next) {
      iGfun[cg->goff+n] = i;
      jGvar[cg->goff+n] = cg->varno;
    }
}

void amplProblem::makePrintName()
{
  char *endptr;
  endptr = strrchr( filename, '/' );
  if ( endptr != NULL ) {
    assert( strlen(endptr+1) < 200 );
    strcpy( printname, endptr+1 );
  } else {
    strcpy( printname, filename );
  }
  endptr = strrchr( printname, '.' );
  if ( endptr != NULL ) {
    *endptr = '\0';
  }
  sprintf( Prob, "%8s", printname );
  strcat( printname, ".out" );
  this->setPrintFile( printname );
}
