/*
 * --- GSMP-COPYRIGHT-NOTE-BEGIN ---
 * 
 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
 * Please add additional copyright information _after_ the line containing
 * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by
 * the ./scripts/Create-CopyPatch script. Do not edit this copyright text!
 * 
 * GSMP: dam/src/SaveDataLexer.cc
 * General Sound Manipulation Program is Copyright (C) 2000 - 2004
 *   Valentin Ziegler and René Rebe
 * 
 * This program 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; version 2. A copy of the GNU General
 * Public License can be found in the file LICENSE.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT-
 * ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 * 
 * --- GSMP-COPYRIGHT-NOTE-END ---
 */

#include "SaveDataLexer.hh"

using namespace DAM;

// TODO: determine correct strtoXX and atoXX functions for int64_t (!!!)

SaveDataLexer::SaveDataLexer (std::istream& input)
  : SaveDataFlexLexer (&input)
{
  last_error = "";
  eof = false;

  // TODO: parse & check  file header
}


bool SaveDataLexer::NextEntity (bool* error, std::string* id, int* version)
{
  if (!Expect ('<', "'<'", true ))
    {
      *error = !Eof ();
      return false;
    }

  if (!Expect (SaveDataTokens::Id, "identifier"))
    {
      *error = true;
      return false;
    }

  *id = yytext;

  int64_t t_version;
  if (!SetInteger (&t_version))
    {
      *error = true;
      return false;
    }

  *version = (int) t_version;
  *error = false;
  return true;
}


bool SaveDataLexer::RecoverToNextEntity (std::string* id, int* version)
{
  bool error;
  bool result;
  do
    result = NextEntity (&error, id, version);
  while (error);
  return result;
};


bool SaveDataLexer::OpenBlock ()
{
  return Expect ('{', "'{'");
}

bool SaveDataLexer::CloseBlock ()
{
  return Expect ('}', "'}'");
}


bool SaveDataLexer::SkipBlock ()
{
  if (!Expect ('{', "'{'"))
    return false;

  int braces = 1;

  while (braces > 0)
    switch (NextToken ())
      {
      case '{':
	braces++;
	break;
      case '}':
	braces--;
	break;
      case 0:
	last_error = "file ends in block";
	return false;
	break;
      }

  return true;
}


bool SaveDataLexer::OpenArray ()
{
  return Expect ('{', "'{'");
}


bool SaveDataLexer::NextArrayItem (bool* error)
{
  int t_token = NextToken ();
  switch (t_token)
    {
    case '-' :
      *error = false; return true;
    case '}':
      *error = false; return false;
    }
  *error = true;
  last_error = "expected '-' or '}'";
  return false;
}


WrapPointer::save_id_t SaveDataLexer::NextEntityElement (bool* error)
{
  WrapPointer::save_id_t r_ptr;

  int t_token = NextToken ();
  switch (t_token)
    {
    case SaveDataTokens::Pointer :
      r_ptr = strtoll (yytext, 0, 16);

      *error = false;
      return r_ptr;

    case '>':
      *error = false;
      return 0;
    }

  *error = true;
  last_error = "expected '>' or Pointer";
  return 0;    
};


bool SaveDataLexer::SetInteger (int64_t* dst)
{
  if (!Expect (SaveDataTokens::Integer, "integer"))
    return false; 

  long long val = atoll (yytext);
  *dst = val;
  return true;
}


bool SaveDataLexer::SetFloat (double* dst)
{
  if (!Expect (SaveDataTokens::Float, "floating point number"))
    return false; 

  double val = atof (yytext);
  *dst = val;
  return true;
}


bool SaveDataLexer::SetString (std::string* dst)
{
  if (!Expect (SaveDataTokens::String, "string constant"))
    return false; 
    
  *dst = SaveDataTokens::const_string;
  return true;
}


bool SaveDataLexer::SetPtr (WrapPointer* dst)
{
  if (!Expect (SaveDataTokens::Pointer, "pointer"))
    return false;

  dst -> Id ( (WrapPointer::save_id_t) strtoll (yytext, 0, 16) );
  return true;
}


int SaveDataLexer::NextToken ()
{
  int r_token = yylex ();
  if (r_token == 0)
    eof = true;
  return r_token;
}

bool SaveDataLexer::Expect (int token, const char* text, bool tolerate_eof)
{
  if (NextToken () != token && !(tolerate_eof && Eof ()))
    {
      last_error = "expected ";
      last_error += text;
      if (Eof ())
	last_error = "reached end of file, " + last_error;
      return false;
    }
  return true;
}


