// This module implements the QextScintillaLexerSQL class.
//
// Copyright (c) 2006
// 	Riverbank Computing Limited <info@riverbankcomputing.co.uk>
// 
// This file is part of QScintilla.
// 
// This copy of QScintilla 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.
// 
// QScintilla is supplied 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
// QScintilla; see the file LICENSE.  If not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


#include <qcolor.h>
#include <qfont.h>
#include <qsettings.h>

#include "qextscintillalexersql.h"


// The ctor.
QextScintillaLexerSQL::QextScintillaLexerSQL(QObject *parent,const char *name)
	: QextScintillaLexer(parent,name), fold_comments(FALSE),
	  fold_compact(TRUE), backslash_escapes(FALSE)
{
}


// The dtor.
QextScintillaLexerSQL::~QextScintillaLexerSQL()
{
}


// Returns the language name.
const char *QextScintillaLexerSQL::language() const
{
	return "SQL";
}


// Returns the lexer name.
const char *QextScintillaLexerSQL::lexer() const
{
	return "sql";
}


// Return the style used for braces.
int QextScintillaLexerSQL::braceStyle() const
{
	return Operator;
}


// Returns the foreground colour of the text for a style.
QColor QextScintillaLexerSQL::color(int style) const
{
	switch (style)
	{
	case Default:
		return QColor(0x80,0x80,0x80);

	case Comment:
	case CommentLine:
	case PlusPrompt:
	case PlusComment:
	case CommentLineHash:
		return QColor(0x00,0x7f,0x00);

	case CommentDoc:
		return QColor(0x7f,0x7f,0x7f);

	case Number:
		return QColor(0x00,0x7f,0x7f);

	case Keyword:
		return QColor(0x00,0x00,0x7f);

	case DoubleQuotedString:
	case SingleQuotedString:
		return QColor(0x7f,0x00,0x7f);

	case PlusKeyword:
		return QColor(0x7f,0x7f,0x00);

	case Operator:
	case Identifier:
		break;

	case CommentDocKeyword:
		return QColor(0x30,0x60,0xa0);

	case CommentDocKeywordError:
		return QColor(0x80,0x40,0x20);

	case KeywordSet5:
		return QColor(0x4b,0x00,0x82);

	case KeywordSet6:
		return QColor(0xb0,0x00,0x40);

	case KeywordSet7:
		return QColor(0x8b,0x00,0x00);

	case KeywordSet8:
		return QColor(0x80,0x00,0x80);
	}

	return QextScintillaLexer::color(style);
}


// Returns the end-of-line fill for a style.
bool QextScintillaLexerSQL::eolFill(int style) const
{
	return (style == PlusPrompt);
}


// Returns the font of the text for a style.
QFont QextScintillaLexerSQL::font(int style) const
{
	QFont f;

	switch (style)
	{
	case Comment:
	case CommentLine:
	case PlusComment:
	case CommentLineHash:
	case CommentDocKeyword:
	case CommentDocKeywordError:
#if defined(Q_OS_WIN)
		f = QFont("Comic Sans MS",9);
#else
		f = QFont("Bitstream Vera Serif",9);
#endif
		break;

	case Keyword:
	case Operator:
		f = QextScintillaLexer::font(style);
		f.setBold(TRUE);
		break;

	case DoubleQuotedString:
	case SingleQuotedString:
	case PlusPrompt:
#if defined(Q_OS_WIN)
		f = QFont("Courier New",10);
#else
		f = QFont("Bitstream Vera Sans Mono",9);
#endif
		break;

	default:
		f = QextScintillaLexer::font(style);
	}

	return f;
}


// Returns the set of keywords.
const char *QextScintillaLexerSQL::keywords(int set) const
{
	if (set == 1)
		return
			"absolute action add admin after aggregate alias all "
			"allocate alter and any are array as asc assertion "
			"at authorization before begin binary bit blob "
			"boolean both breadth by call cascade cascaded case "
			"cast catalog char character check class clob close "
			"collate collation column commit completion connect "
			"connection constraint constraints constructor "
			"continue corresponding create cross cube current "
			"current_date current_path current_role current_time "
			"current_timestamp current_user cursor cycle data "
			"date day deallocate dec decimal declare default "
			"deferrable deferred delete depth deref desc "
			"describe descriptor destroy destructor "
			"deterministic dictionary diagnostics disconnect "
			"distinct domain double drop dynamic each else end "
			"end-exec equals escape every except exception exec "
			"execute external false fetch first float for "
			"foreign found from free full function general get "
			"global go goto grant group grouping having host "
			"hour identity if ignore immediate in indicator "
			"initialize initially inner inout input insert int "
			"integer intersect interval into is isolation "
			"iterate join key language large last lateral "
			"leading left less level like limit local localtime "
			"localtimestamp locator map match minute modifies "
			"modify module month names national natural nchar "
			"nclob new next no none not null numeric object of "
			"off old on only open operation option or order "
			"ordinality out outer output pad parameter "
			"parameters partial path postfix precision prefix "
			"preorder prepare preserve primary prior privileges "
			"procedure public read reads real recursive ref "
			"references referencing relative restrict result "
			"return returns revoke right role rollback rollup "
			"routine row rows savepoint schema scroll scope "
			"search second section select sequence session "
			"session_user set sets size smallint some| space "
			"specific specifictype sql sqlexception sqlstate "
			"sqlwarning start state statement static structure "
			"system_user table temporary terminate than then "
			"time timestamp timezone_hour timezone_minute to "
			"trailing transaction translation treat trigger "
			"true under union unique unknown unnest update usage "
			"user using value values varchar variable varying "
			"view when whenever where with without work write "
			"year zone";

	if (set == 4)
		return
			"acc~ept a~ppend archive log attribute bre~ak "
			"bti~tle c~hange cl~ear col~umn comp~ute conn~ect "
			"copy def~ine del desc~ribe disc~onnect e~dit "
			"exec~ute exit get help ho~st i~nput l~ist passw~ord "
			"pau~se pri~nt pro~mpt quit recover rem~ark "
			"repf~ooter reph~eader r~un sav~e set sho~w shutdown "
			"spo~ol sta~rt startup store timi~ng tti~tle "
			"undef~ine var~iable whenever oserror whenever "
			"sqlerror";

	return 0;
}


// Returns the user name of a style.
QString QextScintillaLexerSQL::description(int style) const
{
	switch (style)
	{
	case Default:
		return tr("Default");

	case Comment:
		return tr("Comment");

	case CommentLine:
		return tr("Comment line");

	case CommentDoc:
		return tr("JavaDoc style comment");

	case Number:
		return tr("Number");

	case Keyword:
		return tr("Keyword");

	case DoubleQuotedString:
		return tr("Double-quoted string");

	case SingleQuotedString:
		return tr("Single-quoted string");

	case PlusKeyword:
		return tr("SQL*Plus keyword");

	case PlusPrompt:
		return tr("SQL*Plus prompt");

	case Operator:
		return tr("Operator");

	case Identifier:
		return tr("Identifier");

	case PlusComment:
		return tr("SQL*Plus comment");

	case CommentLineHash:
		return tr("# comment line");

	case CommentDocKeyword:
		return tr("JavaDoc keyword");

	case CommentDocKeywordError:
		return tr("JavaDoc keyword error");

	case KeywordSet5:
		return tr("User defined 1");

	case KeywordSet6:
		return tr("User defined 2");

	case KeywordSet7:
		return tr("User defined 3");

	case KeywordSet8:
		return tr("User defined 4");
	}

	return QString::null;
}


// Returns the background colour of the text for a style.
QColor QextScintillaLexerSQL::paper(int style) const
{
	if (style == PlusPrompt)
		return QColor(0xe0,0xff,0xe0);

	return QextScintillaLexer::paper(style);
}


// Refresh all properties.
void QextScintillaLexerSQL::refreshProperties()
{
	setCommentProp();
	setCompactProp();
	setBackslashEscapesProp();
}


// Read properties from the settings.
bool QextScintillaLexerSQL::readProperties(QSettings &qs,const QString &prefix)
{
	int rc = TRUE;
	bool ok, flag;

	// Read the fold comments flag.
	flag = qs.readBoolEntry(prefix + "foldcomments",FALSE,&ok);

	if (ok)
		fold_comments = flag;
	else
		rc = FALSE;

	// Read the fold compact flag.
	flag = qs.readBoolEntry(prefix + "foldcompact",TRUE,&ok);

	if (ok)
		fold_compact = flag;
	else
		rc = FALSE;

	// Read the backslash escapes flag.
	flag = qs.readBoolEntry(prefix + "backslashescapes",FALSE,&ok);

	if (ok)
		backslash_escapes = flag;
	else
		rc = FALSE;

	return rc;
}


// Write properties to the settings.
bool QextScintillaLexerSQL::writeProperties(QSettings &qs,const QString &prefix) const
{
	int rc = TRUE;

	// Write the fold comments flag.
	if (!qs.writeEntry(prefix + "foldcomments",fold_comments))
		rc = FALSE;

	// Write the fold compact flag.
	if (!qs.writeEntry(prefix + "foldcompact",fold_compact))
		rc = FALSE;

	// Write the backslash escapes flag.
	if (!qs.writeEntry(prefix + "backslashescapes",backslash_escapes))
		rc = FALSE;

	return rc;
}


// Return TRUE if comments can be folded.
bool QextScintillaLexerSQL::foldComments() const
{
	return fold_comments;
}


// Set if comments can be folded.
void QextScintillaLexerSQL::setFoldComments(bool fold)
{
	fold_comments = fold;

	setCommentProp();
}


// Set the "fold.comment" property.
void QextScintillaLexerSQL::setCommentProp()
{
	emit propertyChanged("fold.comment",(fold_comments ? "1" : "0"));
}


// Return TRUE if folds are compact.
bool QextScintillaLexerSQL::foldCompact() const
{
	return fold_compact;
}


// Set if folds are compact
void QextScintillaLexerSQL::setFoldCompact(bool fold)
{
	fold_compact = fold;

	setCompactProp();
}


// Set the "fold.compact" property.
void QextScintillaLexerSQL::setCompactProp()
{
	emit propertyChanged("fold.compact",(fold_compact ? "1" : "0"));
}


// Return TRUE if backslash escapes are enabled.
bool QextScintillaLexerSQL::backslashEscapes() const
{
	return backslash_escapes;
}


// Enable/disable backslash escapes.
void QextScintillaLexerSQL::setBackslashEscapes(bool enable)
{
	backslash_escapes = enable;

	setBackslashEscapesProp();
}


// Set the "sql.backslash.escapes" property.
void QextScintillaLexerSQL::setBackslashEscapesProp()
{
	emit propertyChanged("sql.backslash.escapes",(backslash_escapes ? "1" : "0"));
}
