/*
 *  Copyright (c) 2008 Cyrille Berger <cberger@cberger.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version of the License.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "Expression.h"

#include "../Debug.h"
#include "../FunctionDeclaration.h"
#include "../Macros_p.h"
#include "../Utils_p.h"
#include "../Variable.h"

#include "GenerationVisitor.h"
#include <complex>

using namespace Cauchy::AST;

void Expression::generateStatement( GenerationVisitor* _generationVisitor) const
{
  _generationVisitor->generateExpression(generateValue(_generationVisitor), comment(), annotation());
}

//------------------------------------------//
//------------- ProxyExpression ------------//
//------------------------------------------//

ExpressionResultSP ProxyExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return m_clone->generateValue(_generationVisitor);
}

//------------------------------------------//
//--------- FunctionCallExpression ---------//
//------------------------------------------//

FunctionCallExpression::FunctionCallExpression( const Cauchy::Variable* _variable, std::list< Cauchy::AST::Expression* > _arguments, std::vector< Cauchy::AST::Expression* > _returns ) : m_function(_variable->name()), m_variable(_variable), m_arguments(_arguments), m_returns(_returns), m_declaration(0)
{
}

FunctionCallExpression::FunctionCallExpression( const String& _function, const Cauchy::FunctionDeclaration* declaration, std::list<Expression*> _arguments, std::vector<Expression*> _returns ) : m_function(_function), m_variable(0), m_arguments(_arguments), m_returns(_returns), m_declaration(declaration)
{
}

FunctionCallExpression::~FunctionCallExpression()
{
  deleteAll( m_arguments );
}

ExpressionResultSP FunctionCallExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateFunctionCall( m_function, m_declaration, m_variable, m_arguments, m_returns, annotation() );
}

const Cauchy::Type* Cauchy::AST::FunctionCallExpression::type() const
{
  if(not m_declaration)
  {
    return Type::Void;
  } else if(m_declaration->returns().empty())
  {
    return Type::Void;
  } else {
    return m_declaration->returns()[0];
  }
}

// NumberExpression

ExpressionResultSP NumberExpression::generateValue(GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateNumber(m_val, m_numberType, annotation());
}

const Cauchy::Type* NumberExpression::type() const
{
  return Cauchy::Type::defaultType();
}

ExpressionResultSP ComplexNumberExpression::generateValue(GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateComplexNumber(m_real, m_imag, m_numberType, annotation());
}

const Cauchy::Type* ComplexNumberExpression::type() const
{
  return Cauchy::Type::complexType(Cauchy::Type::defaultType());
}

ExpressionResultSP StringExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateString(m_string, annotation());
}

ExpressionResultSP FunctionHandleExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateFunctionHandle(m_identifier, annotation());
}

RangeExpression::RangeExpression(Expression* startExpression, Expression* endExpression) : m_startExpression(startExpression), m_endExpression(endExpression), m_stepExpression(0)
{
  RangeExpression* r = dynamic_cast<RangeExpression*>(startExpression);
  if(r)
  {
    m_stepExpression = r->m_endExpression;
    m_startExpression = r->m_startExpression;
    r->m_endExpression = 0;
    r->m_startExpression = 0;
    delete r;
  }
}

RangeExpression::~RangeExpression()
{
  delete m_startExpression;
  delete m_endExpression;
  delete m_stepExpression;
}

ExpressionResultSP RangeExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateRangeExpression(m_startExpression->generateValue(_generationVisitor), m_endExpression->generateValue(_generationVisitor), m_stepExpression ? m_stepExpression->generateValue(_generationVisitor) : 0, annotation() );
}

InfiniteRangeExpression::InfiniteRangeExpression() {}
InfiniteRangeExpression::~InfiniteRangeExpression() {}
ExpressionResultSP InfiniteRangeExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateInfiniteRangeExpression();
}

MatrixExpression::MatrixExpression( const std::vector< std::vector<AST::Expression*> >& expressions) : m_expressions(expressions)
{
  const Cauchy::Type* eType = Cauchy::Type::defaultType();
  for(std::size_t i = 0; i < expressions.size(); ++i)
  {
    for(std::size_t j = 0; j < expressions[i].size(); ++j)
    {
      if(expressions[i][j]->type()->isComplex())
      {
        eType = Cauchy::Type::complexType(Cauchy::Type::defaultType());
        break;
      }
    }
  }
  m_type = Cauchy::Type::matrixType(eType);
}

MatrixExpression::~MatrixExpression()
{
//   deleteAll(m_expressions);
}

ExpressionResultSP MatrixExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  std::list<ExpressionResultSP> results;
  foreach(std::vector<Expression*> row, m_expressions)
  {
    foreach(Expression* el, row)
    {
      results.push_back(el->generateValue(_generationVisitor));
    }
  }
  return _generationVisitor->generateMatrixExpression(m_type, m_expressions.size(), m_expressions[0].size(), results, annotation());
}

VariableExpression::VariableExpression( Cauchy::Variable* var, Expression* idx1, Expression* idx2) : m_var(var), m_idx1(idx1), m_idx2(idx2)
{
}

VariableExpression::~VariableExpression()
{
}

Cauchy::Variable* VariableExpression::variable() const
{
  return m_var;
}

ExpressionResultSP VariableExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  ExpressionResultSP idx1 = 0;
  ExpressionResultSP idx2 = 0;
  if(m_idx1) idx1 = m_idx1->generateValue(_generationVisitor);
  if(m_idx2) idx2 = m_idx2->generateValue(_generationVisitor);
  return _generationVisitor->generateVariable(m_var, idx1, idx2, annotation());
}

const Cauchy::Type* VariableExpression::type() const
{
  return m_var->type();
}

GroupExpression::~GroupExpression()
{
  delete m_expr;
}

ExpressionResultSP GroupExpression::generateValue( GenerationVisitor* _generationVisitor) const
{
  return _generationVisitor->generateGroupExpression( m_expr->generateValue(_generationVisitor), annotation());  
}

const Cauchy::Type* GroupExpression::type() const
{
  return m_expr->type();
}
