#include "parser.h"
#include "nodes.h"
#define YYSTYPE FormulaNode*
#include "bison_parser.tab.hpp"

#include <klocale.h>
#include <kdebug.h>

int yyparse( void );

Parser* Parser::sInstance = 0;

Parser* Parser::instance()
{
  if ( ! sInstance ) sInstance = new Parser;
  return sInstance;
}

Parser::Parser()
  : mParsed( false ),
    mA( 0 ),
    mB( 0 ),
    mC( 0 ),
    mString( 0 ),
    mError( 0 ),
    mPos( 0 ),
    mOutput( 0 )
{

}

bool Parser::parse( const QString s )
{
  // this is a simple struct that makes sure we call
  // FormulaNode::deleteAll() on exiting this function...
  // --> to avoid memory leaks...
  struct CallFNDA
  {
    ~CallFNDA() { FormulaNode::deleteAll(); };
  };
  CallFNDA d;

  kdDebug() << "Before parsing: " << endl
            << s << endl;

  mPos = 0;
  mString = s.utf8();
  if( mString.right( 1 ) != "\n" ) mString += '\n';
  if( yyparse() != 0 )
    return false;

  assert( mOutput );
  kdDebug() << endl << "after parsing, before simplifying: " << endl << *mOutput << endl;
  mOutput = mOutput->simplify();
  kdDebug() << endl << "after simplifying: " << endl << *mOutput << endl;

  // we've got our hierarchy, now parse it down to a parabolic
  // function...
  bool gotA = false;
  bool gotB = false;
  bool gotC = false;

  SumNode* m = dynamic_cast<SumNode*>( mOutput );
  if ( ! m )
  {
    FormulaNode::vec v;
    v.push_back( mOutput );
    m = new SumNode( v );
  };
  for( FormulaNode::vec::iterator i = m->fs.begin(); i != m->fs.end(); ++i )
  {
    double d = (*i)->degree();
    if( static_cast<double>(static_cast<int>(d)) != d )
    {
      mError = i18n( "This is not a parabolic function..." );
      return false;
    };
    if( d > 2 || d < 0 )
    {
      mError = i18n( "This is not a parabolic function..." );
      return false;
    };
    if( d == 2 ) { mA = (*i)->value(); gotA = true; }
    else if( d == 1 ) { mB = (*i)->value(); gotB = true; }
    else if( d == 0 ) { mC = (*i)->value(); gotC = true; };
  };
  if( ! gotA ) { mA = 0; gotA = true; };
  if( ! gotB ) { mB = 0; gotB = true; };
  if( ! gotC ) { mC = 0; gotC = true; };
  return mParsed = true;
}

void Parser::yyinput( char* buf, int& result, int max_size )
{
  QCString tmp = mString.mid( mPos, max_size );
  // hack, i know, but seems correct on all UN*X systems, which is
  // KDE's audience, last time i checked...
#define YY_NULL 0;
  if( tmp.isNull() ) { result = YY_NULL; return; };
  result = tmp.length();
  mPos += result;
  memcpy( buf, tmp.data(), result );
}
void Parser::setOutput( FormulaNode* n )
{
  mOutput = n;
}

Parser* Parser::newInstance()
{
  delete sInstance;
  sInstance = 0;
  return instance();
}

Parser::~Parser()
{

}
