/*
   Copyright (C) 1998-2004 Scott Dattalo

This file is part of gpsim.

gpsim 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, or (at your option)
any later version.

gpsim 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 the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with gpsim; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#include "ValueCollections.h"
#include "symbol.h"

IIndexedCollection::IIndexedCollection(int iAddressRadix) {
  SetAddressRadix(iAddressRadix);
}

void IIndexedCollection::SetAddressRadix(int iRadix) {
  m_iAddressRadix = iRadix;
  if(iRadix == 16) {
    strcpy(m_szPrefix, "$");
  }
  else {
    m_szPrefix[0] = 0;
  }
}

void IIndexedCollection::Set(Value * pValue) {
  unsigned int  uUpper = GetUpperBound() + 1;
  for(unsigned int uIndex = GetLowerBound(); uIndex < uUpper; uIndex++) {
    SetAt(uIndex, pValue);
  }
}

void IIndexedCollection::SetAt(ExprList_t* pIndexers, Expression *pExpr) {
  ExprList_t::iterator it;
  ExprList_t::iterator itEnd = pIndexers->end();
  Value * pValue = pExpr->evaluate();
//    _CT * pCTValue = dynamic_cast<_CT*>(pValue);
//    if(pCTValue != NULL) {
    for(it = pIndexers->begin(); it != itEnd; it++) {
      Value * pIndex = (*it)->evaluate();
      Integer *pIntIndex = dynamic_cast<Integer*>(pIndex);
      if(pIntIndex != NULL) {
        SetAt(int(*pIntIndex), pValue);
      }
      else {
        AbstractRange *pRange = dynamic_cast<AbstractRange*>(pIndex);
        if(pRange) {
          unsigned uEnd = pRange->get_rightVal() + 1;
          for(unsigned int uIndex = pRange->get_leftVal(); uIndex < uEnd; uIndex++) {
            SetAt(uIndex, pValue);
          }
        }
        else {
          register_symbol *pReg = dynamic_cast<register_symbol*>(pIndex);
          if(pReg) {
            SetAt(pReg->getReg()->address, pValue);
          }
          else {
            throw Error("indexer not valid");
          }
        }
      }
      if(pIndex != NULL) {
        delete pIndex;
      }
    }
//    }
//    else {
//    }
  delete pValue;
}

char *IIndexedCollection::toString(char *pBuffer, int len) {
  return strncpy(pBuffer, toString().c_str(), len);
}

string IIndexedCollection::toString() {
  int iColumnWidth = 0;
  vector<string> asIndexes;
  vector<string> asValue;
  ConsolidateValues(iColumnWidth, asIndexes, asValue);
  return toString(iColumnWidth, asIndexes, asValue);
}

#if  1
string IIndexedCollection::toString(ExprList_t* pIndexerExprs) {
  try {
    ostringstream sOut;
    if(pIndexerExprs==NULL)  {
      sOut << toString() << ends;
      return sOut.str();
    }
    else {
      ExprList_t::iterator it;
      ExprList_t::iterator itEnd = pIndexerExprs->end();
      for(it = pIndexerExprs->begin(); it != itEnd; it++) {
        Value * pIndex = (*it)->evaluate();
        AbstractRange *pRange = dynamic_cast<AbstractRange*>(pIndex);
        if(pRange) {
          unsigned uEnd = pRange->get_rightVal() + 1;
          for(unsigned int uIndex = pRange->get_leftVal(); uIndex < uEnd; uIndex++) {
            Value &Value = GetAt(uIndex);
            sOut << Value.name() << " = " << Value.toString() << endl;
          }
          continue;
        }
        Integer *pInt;
        String *pName = dynamic_cast<String*>(pIndex);
        if(pName) {
          pInt = get_symbol_table().findInteger(pName->getVal());
        }
        else {
          pInt = dynamic_cast<Integer*>(pIndex);
        }
        Integer temp(0);
        if(pInt == NULL) {
          // This is a temp workaround. I would expect a register symbol
          // evaluate to an Integer object containing the value of the
          // register. It currently returns an object that is a copy 
          // of the register_symbol object.
          register_symbol *pReg = dynamic_cast<register_symbol*>(pIndex);
          if(pReg) {
            gint64 i;
            pReg->get(i);
            temp.set(i);
            pInt = &temp;
          }
        }
        if(pInt) {
          unsigned int uIndex = (unsigned int)pInt->getVal();
          if(bIsIndexInRange(uIndex)) {
            Value &Value = GetAt(uIndex);
            sOut << Value.name() << " = " << Value.toString() << endl;
          }
          else {
            sOut << "Error: Index " << uIndex << " is out of range" << endl;
          }
        }
        else {
          sOut << "Error: The index specified for '"
            << name() << "' does not contain a valid index."
            << endl;
        }
        delete pIndex;
      }
    }
    sOut << ends;
    return sOut.str();
  }
  catch(Error e) {
    return e.toString();
  }
}
#endif

void IIndexedCollection::PushValue(int iFirstIndex, int iCurrentIndex,
                                   Value *pValue,
                                   vector<string> &asIndexes, vector<string> &asValue) {
  ostringstream sIndex;
  if(m_iAddressRadix == 16) {
    sIndex << hex; 
  }
  sIndex << Value::name() << "[" << m_szPrefix << iFirstIndex;
  if(iFirstIndex != iCurrentIndex) {
    sIndex << ".." << m_szPrefix << iCurrentIndex;
  }
  sIndex << "]" << ends;
  asIndexes.push_back(string(sIndex.str()));
  asValue.push_back(pValue->toString());
}

string IIndexedCollection::ElementIndexedName(unsigned int iIndex) {
  ostringstream sIndex;
  if(m_iAddressRadix == 16) {
    sIndex << hex; 
  }
  sIndex << Value::name() << "[" << m_szPrefix << iIndex;
  sIndex << "]" << ends;
  return sIndex.str();
}

string IIndexedCollection::toString(int iColumnWidth, vector<string> &asIndexes,
                                    vector<string> &asValue) {
  ostringstream sOut;
  vector<string>::iterator itValue;
  vector<string>::iterator itElement;
  vector<string>::iterator itElementEnd = asIndexes.end();
  // Dump the consolidated element list
  for(itElement = asIndexes.begin(), itValue = asValue.begin();
      itElement != itElementEnd;
      itElement++, itValue++) {
    sOut.width(iColumnWidth);
    sOut.setf(ios_base::left);
    sOut << (*itElement);
    sOut << " = ";
    sOut << (*itValue);
    if(itElement + 1 != itElementEnd)
      sOut << endl;
  }
  sOut << ends;
  return sOut.str();
}

Integer * IIndexedCollection::FindInteger(const char *s) {
  return get_symbol_table().findInteger(s);
}



syntax highlighted by Code2HTML, v. 0.9.1