/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set et sw=2 ts=2: */
/***************************************************************************
 *            highlight.cc
 *
 *  Tue Mar 29 09:12:06 CEST 2011
 *  Copyright 2011 Bent Bisballe Nyeng
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *  This file is part of Pracro.
 *
 *  Pracro 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 of the License, or
 *  (at your option) any later version.
 *
 *  Pracro 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 Pracro; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#include "highlight.h"

#include <QXmlStreamWriter>

typedef enum {
  none,
  intag,
  instring,
  inname,
  inattribute
} xml_state_t;

static bool isChar(QChar c)
{
  return
    (c >= 'a' && c <= 'z') ||
    (c >= 'A' && c <= 'Z') ||
    c == '_';
}
 
static QString highlight_xml(QString code)
{
  QString out;
  xml_state_t state = none;
  bool hasname = false;

  QString::iterator c = code.begin();
  while(c != code.end()) {
    if(*c == '<') {
      out += "<span class=\"brackets\">&lt;</span>";
      state = intag;
      hasname = false;
    } else if(state == intag && *c == '>') {
      out += "<span class=\"brackets\">&gt;</span>";
      state = none;
    } else if(state == intag && *c == '/') {
      out += "<span class=\"brackets\">/</span>";

    } else if(state == intag && hasname == false && isChar(*c)) {
      state = inname;
      hasname = true;
      out += "<span class=\"tag\">" + QString(*c);
    } else if(state == inname && isChar(*c)) {
      out += *c;
    } else if(state == inname) {
      out += "</span>" + QString(*c);
      state = intag;

    } else if(state == intag && hasname == true && isChar(*c)) {
      state = inattribute;
      out += "<span class=\"attribute\">" + QString(*c);
    } else if(state == inattribute && isChar(*c)) {
      out += *c;
    } else if(state == inattribute) {
      out += "</span>" + QString(*c);
      state = intag;

    } else if(state == intag && *c == '\"') {
      state = instring;
      out += "<span class=\"string\">&quot;";
    } else if(state == instring && *c == '\"') {
      state = intag;
      out += "&quot;</span>";
    } else if(state == instring) {
      out += *c;

    } else out += *c;
    c++;
  }
  
  /*
  QXmlStreamWriter w(&e->code);
  w.writeCharacters(line + "\n");
  */

  return out;
}

static bool isLuaChar(QChar c)
{
  return
    (c >= 'a' && c <= 'z') ||
    (c >= 'A' && c <= 'Z') ||
    c == '_';
}

static bool isKeyword(QString code)
{
  return code == "if" ||
    code == "then" ||
    code == "else" ||
    code == "end" ||
    code == "this" ||
    code == "function" ||
    code == "local" ||
    code == "and" ||
    code == "or" ||
    code == "not";
}

static QString highlight_lua(QString code)
{
  QString out;
  QString word;

  bool instring = false;

  QString::iterator c = code.begin();
  while(c != code.end()) {
    if(isLuaChar(*c)) {
      word += *c;
    } else {
      if(instring && *c == '\'') {
        out += word + "'</span>";
        instring = false;
      } else if(instring) {
        out += word + QString(*c);
      } else if(isKeyword(word)) {
        out += "<span class=\"keyword\">"+word+"</span>" + QString(*c);
      } else if(*c == '(') {
        out += "<span class=\"function\">"+word+"</span>" + QString(*c);
      } else if(instring == false && *c == '\'') {
        out += word + "<span class=\"string\">'";
        instring = true;
      } else {
        out += word + QString(*c);
      }
      word = "";
    }
    
    c++;
  }

  return out;
}

QString highlight(QString code, lang_t lang)
{
  switch(lang) {
  case lua:
    return highlight_lua(code);
  case xml:
    return highlight_xml(code);
  }
}