/***************************************************************************
**
**  This file is part of dinvermatlab.
**
**  This file is distributed under the terms of the Geopsy.org Commercial
**  License appearing in the file LICENSE.COMMERCIAL included in the packaging
**  of this file.
**
**  This file 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 Geopsy.org Commercial License for
**  more details.
**
**  You should have received a copy of the Geopsy.org Commercial License
**  along with this program. If not, see <http://www.geopsy.org>.
**
**  See http://www.geopsy.org for more information.
**
**  Created : 2008-11-23
**  Authors :
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifdef GP_MATLAB_LIBS
#include <engine.h>
#endif

#include <QGpCoreTools.h>
#include "MatlabTarget.h"

/*!
  \class MatlabTarget MatlabTarget.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

const QString MatlabTarget::xmlMatlabTargetTag="MatlabTarget";

MatlabTarget::MatlabTarget(const MatlabTarget& o)
    : XMLClass()
{
  _startup=o._startup;
  _scriptPath=o._scriptPath;
  _initScript=o._initScript;
  _forwardScript=o._forwardScript;
}

void MatlabTarget::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
{
  TRACE;
  Q_UNUSED(context)
  writeProperty(s, "startup", _startup);
  writeProperty(s, "scriptPath", _scriptPath);
  writeProperty(s, "initScript", _initScript);
  writeProperty(s, "forwardScript", _forwardScript);
}

XMLMember MatlabTarget::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  if(tag=="startup" ) return XMLMember(0);
  else if(tag=="scriptPath" ) return XMLMember(1);
  else if(tag=="initScript" ) return XMLMember(2);
  else if(tag=="forwardScript" ) return XMLMember(3);
  else return XMLMember(XMLMember::Unknown);
}

bool MatlabTarget::xml_setProperty(XML_SETPROPERTY_ARGS)
{
  TRACE;
  Q_UNUSED(tag)
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  switch (memberID) {
  case 0: _startup=content.toString(); return true;
  case 1: _scriptPath=content.toString(); return true;
  case 2: _initScript=content.toString(); return true;
  case 3: _forwardScript=content.toString(); return true;
  default: return false;
  }
}

/*
  Try the Matlab engine and check if function dinverForward() is available
*/
bool MatlabTarget::isOk(int nParams)
{
  TRACE;
  if(isEmpty()) {
    return true;
  }
#ifdef GP_MATLAB_LIBS
  App::log(tr("Testing scripts ...\n") );
  App::setStreamPrefix("[Testing] ");
  Engine * matlab=engOpen(_startup.toLatin1().data());
  if( ! matlab) {
    App::log(tr("Error starting Matlab engine.\n") );
    App::setStreamPrefix("");
    return false;
  }
  char buffer[MATLAB_OUTPUT_BUFFER_SIZE];
  buffer[MATLAB_OUTPUT_BUFFER_SIZE-1]='\0';
  engOutputBuffer(matlab, buffer, MATLAB_OUTPUT_BUFFER_SIZE);
  if(!_scriptPath.isEmpty()) {
    QString cmd="addpath('" + _scriptPath + "');";
    App::log(cmd << endl;
    if(engEvalString( matlab, cmd.toLatin1().data())!=0) {
      App::log(tr("Error adding path '%1'.\n").arg(_scriptPath) );
      if(buffer[0]!='\0') App::log(buffer+4 << endl;
      engClose(matlab);
      App::setStreamPrefix("");
      return false;
    }
  }
  if(buffer[0]!='\0') App::log(buffer+4 << endl;
  App::log(_initScript << endl;
  if(engEvalString( matlab, _initScript.toLatin1().data())!=0) {
    App::log(tr("Error running initialization script '%1' in Matlab environment.\n").arg(_initScript) );
    if(buffer[0]!='\0') App::log(buffer+4 << endl;
    engClose(matlab);
    App::setStreamPrefix("");
    return false;
  }
  if(buffer[0]!='\0') App::log(buffer+4 << endl;
  mxArray * dinverModel=mxCreateDoubleMatrix(1, nParams, mxREAL);
  for(int i=0; i<nParams;i++) {
    mxGetPr(dinverModel)[i]=0.0;
  }
  if(engPutVariable( matlab, "dinverModel", dinverModel)!=0) {
    App::log(tr("Error setting variable dinverModel in Matlab environment.\n") );
    mxDestroyArray(dinverModel);
    engClose(matlab);
    App::setStreamPrefix("");
    return false;
  }
  mxArray * dinverOk=mxCreateLogicalScalar(true);
  if(engPutVariable( matlab, "dinverOk", dinverOk)!=0) {
    App::log(tr("Error setting variable dinverOk in Matlab environment.\n") );
    mxDestroyArray(dinverOk);
    engClose(matlab);
    App::setStreamPrefix("");
    return false;
  }
  App::log(_forwardScript << endl;
  if(engEvalString( matlab, _forwardScript.toLatin1().data())!=0) {
    App::log(tr("Error running forward script '%1' in Matlab environment.\n").arg(_forwardScript) );
    if(buffer[0]!='\0') App::log(buffer+4 << endl;
    engClose(matlab);
    App::setStreamPrefix("");
    return false;
  }
  if(buffer[0]!='\0') App::log(buffer+4 << endl;
  mxArray * dinverMisfit=engGetVariable(matlab, "dinverMisfit" );
  if( ! dinverMisfit) {
    App::log(tr("Error retreiving variable 'dinverMisfit' from Matlab environment.\n") );
    engClose(matlab);
    App::setStreamPrefix("");
    return false;
  }
  if(mxGetNumberOfDimensions( dinverMisfit)!=2 ||
       mxGetDimensions(dinverMisfit)[0]!=1 ||
       mxGetDimensions(dinverMisfit)[1]!=1) {
    App::log(tr("Error variable 'dinverMisfit' is not a scalar.\n") );
    engClose(matlab);
    App::setStreamPrefix("");
    return false;
  }
  mxDestroyArray(dinverMisfit);
  engClose(matlab);
  App::setStreamPrefix("");
  return true;
#else
  Q_UNUSED(nParams)
  App::log(tr("Matlab engine not available, check your configuration.\n") );
  return false;
#endif
}
