int
OperatorUtils::SaveMatrix( const QString& inFileName, const Param& inParam )
{
  if( inFileName.isEmpty() )
    return CouldNotWrite;

  bool saveAsMatrix = ( QFileInfo( inFileName ).suffix() == MATRIX_EXTENSION );
  if( !saveAsMatrix )
  {
    bool isNested = false;
    for( int row = 0; row < inParam.NumRows(); ++row )
      for( int col = 0; col < inParam.NumColumns(); ++col )
        isNested = isNested | ( inParam.Value( row, col ).Kind() != Param::ParamValue::Single );

    if( isNested )
      return CannotWriteNestedMatrixAsText;
  }

  ofstream output( inFileName.toLocal8Bit() );
  if( saveAsMatrix )
  {
    output << inParam;
  }
  else
  {
    for( int row = 0; row < inParam.NumRows(); ++row )
    {
      int col = 0;
      while( col < inParam.NumColumns() - 1 )
        output << inParam.Value( row, col++ ) << '\t';
      output << inParam.Value( row, col ) << endl;
    }
  }
  return output ? NoError : CouldNotWrite;
}
int
OperatorUtils::LoadMatrix( const QString& inFileName, Param& outParam )
{
  if( inFileName.isEmpty() )
    return MatNotFound;

  if( QFileInfo( inFileName ).suffix() == MATRIX_EXTENSION )
  {
    ParamList paramsFromFile;
    paramsFromFile.Load( inFileName.toLocal8Bit().constData(), true );
    if( paramsFromFile.Size() == 0 )
      return MatNotFound;
    if( paramsFromFile.Size() > 1 )
      return MatMultipleParams;
    Param p = paramsFromFile[0];
    outParam.SetDimensions( p.NumRows(), p.NumColumns() );
    for( int row = 0; row < p.NumRows(); ++row )
      for( int col = 0; col < p.NumColumns(); ++col )
        outParam.Value( row, col ) = p.Value( row, col );
    outParam.RowLabels() = p.RowLabels();
    outParam.ColumnLabels() = p.ColumnLabels();
  }
  else
  {
    ifstream input( inFileName.toLocal8Bit() );
    input.clear();
    vector<vector<string> > matrix;
    string line;
    while( getline( input, line ) )
    {
      istringstream is( line );
      vector<string> row;
      string value;
      while( getline( is, value, '\t' ) )
        row.push_back( value );
      if( !row.empty() )
        matrix.push_back( row );
    }
    if( matrix.empty() )
      return MatNotFound;

    size_t numRows = matrix.size(),
    numCols = matrix[ 0 ].size();
    for( size_t row = 1; row < numRows; ++row )
      if( matrix[ row ].size() != numCols )
        return MatLoadColsDiff;

    outParam.SetDimensions( numRows, numCols );
    for( size_t row = 0; row < numRows; ++row )
      for( size_t col = 0; col < numCols; ++col )
      {
        istringstream iss( matrix[ row ][ col ] );
        iss >> outParam.Value( row, col );
      }
  }
  return NoError;
}
////////////////////////////////////////////////////////////////////////////////
// MatlabEngine::StringMatrix definitions                                     //
////////////////////////////////////////////////////////////////////////////////
MatlabEngine::StringMatrix::StringMatrix( const Param& p )
    : vector<vector<string> >( p.NumRows(), vector<string>( p.NumColumns() ) )
{
    for( size_t row = 0; row < size(); ++row )
        for( size_t column = 0; column < ( *this )[ row ].size(); ++column )
            ( *this )[ row ][ column ] = p.Value( row, column );
}
Param*
_TParamDef::param_get_ptr_suffix( ParamList* inList, const char* inName, long inSuffix )
{                                                                               
  Param* result = NULL;
  string _name = inName,
         _blankName = _name;
  unsigned int _replacePos = _name.find( RUNTIME_SUFFIX );
  assert( _replacePos != string::npos );
  _blankName.erase( _replacePos, sizeof( RUNTIME_SUFFIX ) - 1 );
  ostringstream _suffix;
  _suffix << inSuffix;
  _name.replace( _replacePos, sizeof( RUNTIME_SUFFIX ) - 1, _suffix.str() );
  if( inList->Exists( _name ) )
    result = &( *inList )[ _name ];
  else
  {
    static Param p;
    if( inList->Exists( _blankName ) )
    {
      Param& param = ( *inList )[ _blankName ];
      p.SetType( "list" );
      p.SetNumValues( param.NumValues() );
      for( int i = 0; i < param.NumColumns(); ++i )
        p.Value( i ) = param.Value( inSuffix, i );
      result = &p;
    }
  }
  return result;
}
bool
EnvironmentBase::IsAutoConfigParam( const Param& p )
{
  enum { autoType = 0, autoTag, autoKind, count };
  static const char* s[][count] =
  {
    { "blob", 0 },
    { "auto", "AutoConfig", 0 },
    { "(enumeration)", 0 },
  };
  struct
  {
    bool Is( int type, const char* str )
    { 
      const char** p = s[type];
      while( *p )
        if( !::stricmp( *p++, str ) )
          return true;
      return false;
    }
    bool Contains( int type, const char* str )
    { 
      while( *str )
        if( Is( type, str++ ) )
          return true;
      return false;
    }
  } strings;

  bool result = strings.Is( autoType, p.Type().c_str() );
  if( p.NumValues() == 1 )
    result = result || strings.Is( autoTag, p.Value().c_str() );
  if( p.NumValues() > 0 && !::atoi( p.Value().c_str() ) )
    result = result || strings.Contains( autoKind, p.Comment().c_str() )
                       && strings.Contains( autoTag, p.Comment().c_str() );
  return result;
}
void
_TParamDef::param_add_all( ParamList* inList, const char* inSectionPrefix, long inDefaultDimension )
{
  string  sectionPrefix( inSectionPrefix ),
          externalPrefix( "ext_" ),
          runtimeSuffix( RUNTIME_SUFFIX ),
          runtimeElement( RUNTIME_ELEMENT );
  for( list<_TParamDef*>::const_iterator i = _TParamDef::params().begin();
        i != params().end(); ++i )
  {
    Param p( ( *i )->definitionLine() );
    string section = p.Section();
    if( section.find( externalPrefix ) != 0 )
    {
      if( section != sectionPrefix )
      {
         section = sectionPrefix + "_" + section;
         p.SetSection( section );
      }
      string name = p.Name();
      size_t suffixPos = name.find( runtimeSuffix );
      if( suffixPos != name.npos )
      {
        p.SetType( "matrix" );
        string value = p.Value();
        size_t pos = value.find( runtimeSuffix );
        p.SetDimensions( inDefaultDimension + 1, 1 );
        for( int i = p.NumRows() - 1; i >= 0; --i )
        {
          // Replace RUNTIME_SUFFIX in the comment and use it as a row label.
          ostringstream os;
          os << i;
          string comment = p.Comment();
          size_t comment_pos = comment.find( runtimeSuffix );
          if( comment_pos != comment.npos )
            comment.replace( comment_pos, runtimeSuffix.length(), os.str() );
          p.RowLabels()[ i ] = comment;
          // Replace RUNTIME_SUFFIX in the parameter values.
          if( pos == value.npos )
            p.Value( i, 0 ) = value;
          else
          {
            string newValue = value;
            newValue.replace( pos, runtimeSuffix.length(), os.str() );
            p.Value( i, 0 ) = newValue;
          }
        }
        p.ColumnLabels()[ 0 ] = "";

        ostringstream oss;
        oss << p;
        string line = oss.str();
        // Replace RUNTIME_SUFFIX in the parameter name.
        pos = line.find( runtimeSuffix );
        if( pos != line.npos )
          line.replace( pos, runtimeSuffix.length(), "" );
        // Replace RUNTIME_SUFFIX in the comment.
        pos = line.rfind( runtimeSuffix );
        if( pos != line.npos )
          line.replace( pos, runtimeSuffix.length(), "N" );
        name.replace( suffixPos, runtimeSuffix.length(), "" );
        if( !inList->Exists( name ) )
          inList->Add( line );
      }
      else
      { // The parameter might be a special instance for a certain suffix.
        // This will only work for true suffices, i.e. at the end of the name.
        size_t pos = name.find_last_not_of( "0123456789" );
        Param* param = NULL;
        if( pos != name.length() - 1 )
        {
          string paramName = name.substr( 0, pos + 1 );
          if( inList->Exists( paramName ) )
            param = &( *inList )[ paramName ];
        }
        if( param != NULL && string( "matrix" ) == param->Type() )
        {
          long suffix = ::atoi( name.substr( pos ).c_str() );
          param->Value( suffix, 0 ) = p.Value();
          param->RowLabels()[ suffix ] = p.Comment();
        }
        else if( !PARAM_EXISTS( inList, p.Name() ) )
        {
          ostringstream oss;
          oss << p;
          string line = oss.str();
          // Runtime elements are not supported, the user must supply a value.
          size_t rtPos;
          while( ( rtPos = line.find( runtimeElement ) ) != line.npos )
            line.replace( rtPos, runtimeElement.length(), "N/A" );
          inList->Add( line );
        }
      }
    }
  }
}