/***************************************************************************
                        specialinformation.cpp - internal commands information
                             -------------------
    copyright            : (C) 2004 by Michal Rudolf <mrudolf@kdewebdev.org>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
 
#include "specials.h"
#include "specialinformation.h"

#include <tdelocale.h> 

SpecialFunction::SpecialFunction(const TQString& name, const TQString& description,
    int minArgs, int maxArgs)
{
  m_parserTypes = AllParsers;
  int lbracket = name.find('(');
  int rbracket = name.find(')');
  m_function = (lbracket != -1) ? name.left(lbracket) : name;
  m_description = description;
  if (lbracket != -1 && rbracket != -1)
  {
    TQString part = name.mid(lbracket+1, rbracket - lbracket - 1);
    TQStringList args = TQStringList::split(",", part);
    for (uint i=0; i<args.count(); i++)
    {
      m_types.append(args[i].stripWhiteSpace().section(' ', 0, 0));
      m_args.append(args[i].stripWhiteSpace().section(' ', 1, 1));
    }
  }
  m_minArgs = (minArgs == -1) ? m_types.count() : minArgs;
  m_maxArgs = (maxArgs == -1) ? m_types.count() : maxArgs;
}

SpecialFunction::SpecialFunction(ParserType p, const TQString& name, const TQString& description,
    int minArgs, int maxArgs)
{
  m_parserTypes = p;
  int lbracket = name.find('(');
  int rbracket = name.find(')');
  m_function = (lbracket != -1) ? name.left(lbracket) : name;
  m_description = description;
  if (lbracket != -1 && rbracket != -1)
  {
    TQString part = name.mid(lbracket+1, rbracket - lbracket - 1);
    TQStringList args = TQStringList::split(",", part);
    for (uint i=0; i<args.count(); i++)
    {
      m_types.append(args[i].stripWhiteSpace().section(' ', 0, 0));
      m_args.append(args[i].stripWhiteSpace().section(' ', 1, 1));
    }
  }
  m_minArgs = (minArgs == -1) ? m_types.count() : minArgs;
  m_maxArgs = (maxArgs == -1) ? m_types.count() : maxArgs;
}


TQString SpecialFunction::prototype(uint prototypeFlags) const
{
  if (!m_types.count())
    return m_function;
  int start = (prototypeFlags & SkipFirstArgument) ? 1 : 0;
  TQStringList params;
  for (uint i=start; i<m_types.count(); i++)
    if (prototypeFlags & ShowArgumentNames)
      params.append(TQString("%1 %2").arg(m_types[i]).arg(m_args[i]));
    else
      params.append(m_types[i]);
  if (!params.count())
    return m_function;
  else if (prototypeFlags & NoSpaces)
    return TQString("%1(%2)").arg(m_function).arg(params.join(","));
  else
    return TQString("%1(%2)").arg(m_function).arg(params.join(", "));
}

TQString SpecialFunction::argumentName(uint i) const
{
  if (i < m_args.count())
    return m_args[i];
  return TQString();
}

TQString SpecialFunction::argumentType(uint i) const
{
  if (i < m_types.count())
    return m_types[i];
  return TQString();
}

int SpecialFunction::argumentCount() const
{
  return m_types.count();
}




int SpecialInformation::function(int group, const TQString& fname) 
{
  TQString f = fname.lower();
  if (m_functions.contains(group) && m_functions[group].contains(f))
    return m_functions[group][f];
  else if (m_aliases.contains(group) && m_aliases[group].contains(f))
    return m_aliases[group][f];
  return -1;
}
  
SpecialFunction SpecialInformation::functionObject(const TQString& gname, const TQString& fname)
{
  int gid = group(gname);
  return m_specials[gid][function(gid, fname)];
}

int SpecialInformation::group(const TQString& gname) 
{
 if (m_groups.contains(gname))
    return m_groups[gname];
  return -1;  
}

bool SpecialInformation::isValid(int gname, int fname) 
{
  return m_specials.contains(gname) && m_specials[gname].contains(fname);
}

bool SpecialInformation::isValid(const TQString& gname, const TQString& fname) 
{
  return function(group(gname), fname) != -1;
}

bool SpecialInformation::isValid(int gname, int fname, SpecialFunction::ParserType p)
{
  return m_specials.contains(gname) && m_specials[gname].contains(fname)
    && m_specials[gname][fname].isSupported(p);
}

bool SpecialInformation::isValid(const TQString& gname, const TQString& fname,
  SpecialFunction::ParserType p)
{
  int g = group(gname);
  int f = function(g, fname);
  return f != -1 && m_specials[g][f].isSupported(p);
}

int SpecialInformation::minArg(int gname, int fname) 
{
  if (isValid(gname, fname))
    return m_specials[gname][fname].minArg();
  return -1;
}

int SpecialInformation::maxArg(int gname, int fname) 
{
  if (isValid(gname, fname))
    return m_specials[gname][fname].maxArg();
  return -1;
}

int SpecialInformation::argCount(int gname, int fname) 
{
  if (isValid(gname, fname))
    return m_specials[gname][fname].argumentCount();
  return -1;
}

bool SpecialInformation::isValidArg(int gname, int fname, int args) 
{
  if (isValid(gname, fname))
    return m_specials[gname][fname].isValidArg(args);
  return -1;
}

TQString SpecialInformation::description(int gname, int fname)
{
  if (isValid(gname, fname))
    return m_specials[gname][fname].description();
  return TQString();
}

TQString SpecialInformation::prototype(int gname, int fname, uint flags)
{
  if (isValid(gname, fname))
    return m_specials[gname][fname].prototype(flags);
  return TQString();
}

bool SpecialInformation::insert(int id, const TQString& function, const TQString description,
    int minArgs, int maxArgs, SpecialFunction::ParserType pType)
{
  if (isValid(m_defaultGroup, id))  /* function already defined */
    return false;
  if (m_functions[m_defaultGroup].contains(function.lower()))
    return false;                   /* function name already in use */
  if (m_aliases[m_defaultGroup].contains(function.lower()))
    return false;                   /* function name already in use */
  SpecialFunction sf(pType, function, description, minArgs, maxArgs);
  m_specials[m_defaultGroup][id] = sf;
  m_functions[m_defaultGroup][sf.name().lower()] = id;
  return true;
}

bool SpecialInformation::insertMacro(int id, const TQString& function, const TQString description,
    int minArgs, int maxArgs)
{
  return insert(id, function, description, minArgs, maxArgs, SpecialFunction::MacroParser);
}

bool SpecialInformation::insertInternal(int id, const TQString& function, const TQString description,
    int minArgs, int maxArgs)
{
  return insert(id, function, description, minArgs, maxArgs, SpecialFunction::InternalParser);
}

bool SpecialInformation::insertAlias(int id, const TQString& alias)
{
  if (!isValid(m_defaultGroup, id))  /* function doesn't exists */
    return false;
  if (m_functions[m_defaultGroup].contains(alias.lower()))
    return false;
  if (m_aliases[m_defaultGroup].contains(alias.lower()))
    return false;
  m_aliases[m_defaultGroup][alias] = id;
  return true;
}

void SpecialInformation::setDefaultGroup(int gname)  
{
  m_defaultGroup = gname;
}

void SpecialInformation::insertGroup(int id, const TQString& name, const TQString& parserName)
{
  if (group(name) == -1) {
    m_groups[name] = id;
    m_parserGroups[name] = parserName;
    m_defaultGroup = id;
  }
}

TQString SpecialInformation::parserGroupName(const TQString& name)
{
  if (m_parserGroups.contains(name))
    return m_parserGroups[name];
  else
    return name;
}

TQStringList SpecialInformation::groups()
{
  return m_groups.keys();
}

TQStringList SpecialInformation::functions(const TQString& g)
{
  int gid = group(g);
  if (gid == -1)
    return TQStringList();
  else
  {
    TQStringList list;
    const TQMap<int, SpecialFunction> fgroup = m_specials[gid];
    for(TQMap<int, SpecialFunction>::ConstIterator it = fgroup.begin(); it != fgroup.end(); ++it)
       list.append(it.data().name());
    return list;
  }
}

bool SpecialFunction::isSupported(ParserType p) const
{
  return (m_parserTypes & p);
}

void SpecialInformation::registerSpecials()
{
  insertGroup(Group::DCOP, "DCOP", "");
  insert(DCOP::addUniqueItem, "addUniqueItem(TQString widget, TQString item)",
         i18n("Inserts the item if it will not create a duplicate."), 2);
  insert(DCOP::associatedText, "associatedText(TQString widget)",
         i18n("Returns scripts associated with widget. This is an advanced feature that would not be commonly used."), 1);
  insert(DCOP::cancel, "cancel(TQString widget)", i18n("Stops execution of the script associated with the widget."), 1);
  insert(DCOP::cellText, "cellText(TQString widget, int row, int column)",
         i18n("Returns text of a cell in a table."), 3);
  insert(DCOP::checked, "checked(TQString widget)",
         i18n("Returns 1 for checked boxes, 0 for unchecked."), 1);
  insert(DCOP::children, "children(TQString widget, bool recursive)",
         i18n("Returns the list of child widgets contained in the parent widget. Set the <i>recursive</i> parameter to <i>true</i> to include widgets contained by child widgets."), 2);
  insert(DCOP::clear, "clear(TQString widget)",
         i18n("Removes all content from the widget."), 1);
  insertAlias(DCOP::clear, "clearList");
  insertInternal(DCOP::columnCount, "columnCount(TQString widget)", 
        i18n("Get the column count"), 1);
  insert(DCOP::count, "count(TQString widget)",
         i18n("Returns number of items in a widget such as combobox or listbox."), 1);
  insert(DCOP::currentColumn, "currentColumn(TQString widget)", 
         i18n("Returns index of current column."), 1);
  insert(DCOP::currentItem, "currentItem(TQString widget)", 
         i18n("Returns index of current item."), 1);
  insert(DCOP::currentRow, "currentRow(TQString widget)", 
         i18n("Returns index of current row."), 1);
  insert(DCOP::execute, "execute(TQString widget)", 
         i18n("Executes the script associated with the widget. With the new parser the execute method can take one or more arguments."), 1, 9);
  insert(DCOP::findItem, "findItem(TQString widget, TQString item, int column, bool CaseSensitive, bool ExactMatch)",
         i18n("Returns the index of an item with the given text. Defaults to case sensitive. Matching can be an exact match or match if it contains the string. Only the first argument is requred. If no column is given it will search the first by default."), 2, 5);
  insert(DCOP::insertColumn, "insertColumn(TQString widget, int column, int count)",
         i18n("Inserts new column (or <i>count</i> columns) at <i>column</i> position."), 2);
  insert(DCOP::insertItem, "insertItem(TQString widget, TQString item, int index)",
         i18n("Inserts item at <i>index</i> position."), 3);
  insertAlias(DCOP::insertItem, "addListItem");
  insert(DCOP::insertItems, "insertItems(TQString widget, TQStringList items, int index)",
         i18n("Inserts multiple items (EOL-separated) at <i>index</i> position."), 3);
  insertAlias(DCOP::insertItems, "addListItems");
  insert(DCOP::insertRow, "insertRow(TQString widget, int row, int count)",
         i18n("Inserts new row (or <i>count</i> rows) at <i>row</i> position."), 2);
  insert(DCOP::item, "item(TQString widget, int index)",
         i18n("Returns the text of the item at the given index."), 2);
  insert(DCOP::itemDepth, "itemDepth(TQString widget, int index)",
         i18n("Returns the depth of the current item in the tree. Root items have depth 0."), 2);
  insert(DCOP::itemPath, "itemPath(TQString widget, int index)",
         i18n("Returns the slash-separated path to the given item in the tree."), 2);
  insert(DCOP::removeColumn, "removeColumn(TQString widget, int column, int count)",
         i18n("Removes the column (or <i>count</i> consecutive columns) with the given index."), 2, 3);
  insert(DCOP::removeItem, "removeItem(TQString widget, int index)",
         i18n("Removes the item with the given index."), 2);
  insertAlias(DCOP::removeItem, "removeListItem");
  insert(DCOP::removeRow, "removeRow(TQString widget, int row, int count)",
         i18n("Removes the row (or <i>count</i> consecutive rows) with the given index."), 3);
  insertAlias(DCOP::removeItem, "removeListItem");
  insert(DCOP::selection, "selection(TQString widget)", 
         i18n("Returns selected text or text of current item.\nIn case of Table widgets, returns the selection coordinates, separated by commas in TopRow,LeftColumn,BottomRow,RightColumn form. "), 1);
  insert(DCOP::setAssociatedText, "setAssociatedText(TQString widget, TQString text)",
         i18n("Sets scripts associated with widget. This is an advanced feature that would not be commonly used."), 2);
  insert(DCOP::setEnabled, "setEnabled(TQString widget, bool enabled)", 
     i18n("Enables or disables widget."), 2);
  insertAlias(DCOP::setEnabled, "enableWidget");
  insert(DCOP::setCellText, "setCellText(TQString widget, int row, int col, TQString text)",
         i18n("Sets text of a cell in a table."), 4);
  insert(DCOP::setCellWidget, "setCellWidget(TQString widget, int row, int col, TQString cellWidget)",
         i18n("Inserts a widget into a cell of a table."), 4);
  insert(DCOP::cellWidget, "cellWidget(TQString widget, int row, int col)",
         i18n("Returns the name of a widget inserted into a cell, or an empty string if the cell contains no widget or an unknown widget type."), 3);
  insert(DCOP::setChecked, "setChecked(TQString widget, bool checked)",
         i18n("Sets/unsets checkbox."), 2);
  insert(DCOP::setColumnCaption, "setColumnCaption(TQString widget, int column, TQString text)",
         i18n("Sets caption of the column <i>column</i>."), 3);
  insert(DCOP::setCurrentItem, "setCurrentItem(TQString widget, int index)",
         i18n("Selects the item at the specified index. Indexes are zero based."), 2);
  insertAlias(DCOP::setCurrentItem, "setCurrentTab");
  insert(DCOP::insertTab, "insertTab(TQString widget, TQString label,int index)",
         i18n("Inserts a tab to the tabwidget with the specified label at the given index. Indexes are zero based."), 3); //enable for 3.5.8
  insert(DCOP::setMaximum, "setMaximum(TQString widget, int value)",
         i18n("Sets maximum numeric value"), 2);
  insert(DCOP::setPixmap, "setPixmap(TQString widget, TQString iconName, int index)",
         i18n("Sets pixmap at the given index to the specified icon. Use <i>index = -1</i> to set the pixmap for all items."), 3);
  insert(DCOP::setRowCaption, "setRowCaption(TQString widget, int row, TQString text)",
         i18n("Sets caption of the row <i>row</i>."), 3);
  insert(DCOP::setSelection, "setSelection(TQString widget, TQString text)", 
         i18n("Selects given text or select item containing given text."), 2);
  insertAlias(DCOP::setSelection, "setCurrentListItem");
  insert(DCOP::setText, "setText(TQString widget, TQString text)", 
         i18n("Sets widget's content."), 2);
  insertAlias(DCOP::setText, "changeWidgetText");
  insert(DCOP::setVisible, "setVisible(TQString widget, bool visible)", 
         i18n("Shows/hides widget."), 2);
  insert(DCOP::text, "text(TQString widget)", i18n("Returns content of widget."), 1);
  insert(DCOP::type, "type(TQString widget)",
     i18n("Returns type(class) of widget."), 1);
  insert(DCOP::setEditable, "setEditable(TQString widget, bool editable)", 
     i18n("Makes the widget editable or read only, depending on the editable argument."), 2);
  insertInternal(DCOP::geometry, "geometry(TQString widget)", 
     i18n("Return the widget's geometry as <i>x y w h</i>. This is useful for positioning a created widget."), 1);
  insertInternal(DCOP::hasFocus, "hasFocus(TQString widget)", 
     i18n("Returns true if the widget has focus."), 1);
  insertInternal(DCOP::getBackgroundColor, "getBackgroundColor(TQString widget)", 
      i18n("Gets the widget's background color."), 1);
  insertInternal(DCOP::setBackgroundColor, "setBackgroundColor(TQString widget, TQString Color)", 
      i18n("Sets the widget's background color. Colors can be by name, like blue, or in hex like #0000ff for blue. Use the color dialog or a color picker if unsure."), 2);
  insertInternal(DCOP::isModified, "isModified(TQString widget)",
      i18n("See if widget has been modified."), 1);

  insertGroup(Group::Slots, i18n("Slots"), "");

  insertGroup(Group::Kommander, "Kommander", "");
  insertMacro(Kommander::widgetText, "widgetText", 
    i18n("Returns current widget's content. This was required inside widget A to return widget A content when requested by widget B. The new method is to use @A.text inside B instead of just @A if you just want the unaltered text."), 0);
  insertMacro(Kommander::selectedWidgetText, "selectedWidgetText", 
    i18n("Returns selected text or text of current item. This is deprecated for <i>@mywidget.selected</i>."), 0);
  insertMacro(Kommander::null, "null", 
     i18n("Does nothing. This is useful if you request a CheckBox or RadioButton to return a value where a state, typically the unchecked state, has no value. The @null prevents an error indicating it is empty."), 0);
  insert(Kommander::pid, "pid", 
     i18n("Returns the pid (process ID) of the current process."), 0);
  insert(Kommander::dcopid, "dcopid", 
     i18n("Returns DCOP identifier of current process. This is shorthand for <i>kmdr-executor-@pid</i>."), 
     0);
  insert(Kommander::parentPid, "parentPid", 
     i18n("Returns the pid of the parent Kommander window."), 0);
  insert(Kommander::debug, "debug(TQString text)",
         i18n("Writes <i>text</i> on stderr."), 1);
  insert(Kommander::echo, "echo(TQString text)",
         i18n("Writes <i>text</i> on standard output."), 1);
  insertMacro(Kommander::execBegin, "execBegin(TQString shell)", 
     i18n("Executes a script block. Bash is used if no shell is given. It is primarily for use in non-button widgets where script actions are not expected. Full path is not required for the shell which may be useful for portability. <p><i>If this is used inside a button it allows alternate script languages to be used and will return a value to the main script, which may be unexpected.</i>"), 0);
  insert(Kommander::env, "env(TQString variable)",
     i18n("Returns value of an environment (shell) variable. Do not use <i>$</i> in the name. For example, <i>@env(PATH)</i>."), 1);
  insert(Kommander::exec, "exec(TQString command)",
     i18n("Executes an external shell command."), 1);
  insertInternal(Kommander::execBackground, "execBackground(TQString command)",
     i18n("Executes an external shell command."), 1);
  insertMacro(Kommander::expr, "expr(TQString expression)",
     i18n("Parses an expression and returns computed value."), 1);
  insert(Kommander::forEachBlock, "forEach(TQString variable, TQString items)",
     i18n("Executes loop: values from <i>items</i> list (passed as EOL-separated string) are assigned to the variable. <br><b>Old</b><br> <i>@forEach(i,A\\nB\\nC\\n)<br>  @# @i=A<br>@end</i><br><b>New</b><br><i>foreach i in MyArray do<br>  //i = key, MyArray[i] = val<br>end "), 2);
  insert(Kommander::forBlock, "for(TQString variable, int start, int end, int step)",
     i18n("Executes loop: variable is set to <i>start</i> and is increased by <i>step</i> each time loop is executed. Execution stops when variable becomes larger then <i>end</i>. <br><b>Old</b><br><i>@for(i,1,10,1)<br>  @# @i=1<br>@endif</i><br><b>New</b><br><i>for i=0 to 20 step 5 do<br>  debug(i)<br>end</i>."), 3);
  insertMacro(Kommander::global, "global(TQString variable)",
     i18n("Returns the value of a global variable."), 1);
  insert(Kommander::i18n, "i18n(TQString variable)",
     i18n("Translates the string into the current language. Texts in GUI would be automatically extracted for translation."), 1);
  insert(Kommander::ifBlock, "if(TQString expression)",
     i18n("Executes block if expression is true (non-zero number or non-empty string.) <p><b>Old</b>Close with <b>@endif</b></p><p><b>New</b><br>if val == true then<br>//  do op<br>elseif cond<br>//  second chance<br>else<br>//  cond failed<br>endif</p>"), 1);
  insert(Kommander::dialog, "dialog(TQString file, TQString args)",
     i18n("Executes another Kommander dialog. Current dialog directory is used if no path is given. Arguments may be given as named arguments which will become global variables in the new dialog. For instance: <i>var=val</i>"), 1);
  insert(Kommander::readSetting, "readSetting(TQString key, TQString default)",
     i18n("Reads setting from configration file for this dialog."), 2);
  insert(Kommander::setGlobal, "setGlobal(TQString variable, TQString value)",
     i18n("Sets the value of a global variable. Global variables exist for the life of the Kommander window."), 2);
  insert(Kommander::writeSetting, "writeSetting(TQString key, TQString value)",
     i18n("Stores setting in configuration file for this dialog."), 2);
  insertMacro(Kommander::switchBlock, "switch(TQString expresion)",
     i18n("Begin of <b>switch</b> block. Following <b>case</b> values are compared to <i>expression</i>.<p>@switch()<br>@case()<br>@end"), 1);
  insert(Kommander::dcop, "dcop(TQString id, TQString interface, TQString function, TQString args)",
     i18n("Executes an external DCOP call."), 3, 9);
  insertMacro(Kommander::comment, "#",
     i18n("Adds a comment to EOL that Kommander will not parse"), 0);
  insertInternal(Kommander::createWidget, "createWidget(TQString widgetName, TQString widgetType, TQString parent)",
     i18n("Creates a new widget with the specified type and as the child of parent."), 3);
  insertInternal(Kommander::widgetExists, "widgetExists(TQString widgetName)",
     i18n("Returns true if there is a widget with the passed name, false otherwise."), 1);
  insertInternal(Kommander::connect, "connect(TQString sender, TQString signal, TQString receiver, TQString slot)",
     i18n("Connects the signal of sender with the slot of the receiver"), 4);
  insertInternal(Kommander::disconnect, "disconnect(TQString sender, TQString signal, TQString receiver, TQString slot)",
     i18n("Disconnects the signal of sender from the slot of the receiver"), 4);
/*  insertInternal(Kommander::switchInternal, "switch(TQString Variable)",
     i18n("Can use can use <br>switch var<br>case 1<br> //code<br>else<br> //code<br>end<p>also can use the form of <br>switch var {<br>case 1; //code<br>else; code<br>}<p> semicolons are optional in place of returns. Currently switch does not parse value from arrays.") );
*/
  insertInternal(Kommander::exit, "exit", 
     i18n("Exits script execution and returns"), 0);
  insertInternal(Kommander::Break, "break", 
     i18n("Exits the current block of a while, for or foreach loop"), 0);
  insertInternal(Kommander::Continue, "continue", 
     i18n("Exit a step and return to the beginning of a loop"), 0);
  insertInternal(Kommander::Return, "return(TQString value)", 
     i18n("Return from a script, optionaly with a value from the script to the caller"), 0, 1);

  insertGroup(Group::Array, "Array", "array");
  insert(Array::values, "values(TQString array)", 
    i18n("Returns an EOL-separated list of all values in the array."), 1);
  insert(Array::keys,"keys(TQString array)", 
    i18n("Returns an EOL-separated list of all keys in the array."), 1);
  insert(Array::clear,"clear(TQString array)", 
    i18n("Removes all elements from the array."), 1);
  insert(Array::count,"count(TQString array)", 
    i18n("Returns the number of elements in the array."), 1);
  insertMacro(Array::value, "value(TQString array, TQString key)", 
    i18n("Returns the value associated with the given key."), 2);
  insert(Array::remove,"remove(TQString array, TQString key)", 
    i18n("Removes element with the given key from the array."), 2);
  insertMacro(Array::setValue,"setValue(TQString array, TQString key, TQString value)",
    i18n("Adds element with the given key and value to the array"), 3);
  insert(Array::fromString, "fromString(TQString array, TQString string)", 
    i18n("Adds all elements in the string to the array. "
    "String should have <i>key\\tvalue\\n</i> format."), 2);
  insert(Array::toString, "toString(TQString array)", 
    i18n("Returns all elements in the array in <pre>key\\tvalue\\n</pre> format."), 1);
  insertInternal(Array::indexedFromString, "indexedFromString(TQString array, TQString string, TQString separator)", 
    i18n( "Create an integer indexed array - starting from 0 - from a string. Use the separator character to split the string. The separator's default value is '\\t'."), 2, 3);
  insertInternal(Array::indexedToString, "indexedToString(TQString array, TQString separator)", 
    i18n( "Create a string from an integer indexed array. Concatenate the elements with the separator character. The separator's default value is '\\t'."), 1, 2);
  insertInternal(Array::indexedRemoveElements, "indexedRemoveElements(TQString array, int keyStart, int keyNum)", 
    i18n( "Remove keyNum elements starting with keyStart from an indexed array and reindex the array. If keyNum is not specified, remove only the keyStart element."), 2, 3);
  insertInternal(Array::indexedInsertElements, "indexedInsertElements(TQString array, int key, TQString string, TQString separator)", 
    i18n( "Insert the elements from string starting at key and reindex the array. Use the separator to separate the elements from the string. The separator's default value is '\\t'."), 3, 4);
  insertInternal(Array::flipCopy, "flipCopy(TQString Array, TQString Copy)",
    i18n("Create a flipped copy of the array where the keys and values switch places. NOTE: If the values are not unique they will be overwritten as keys! Set the name of the array to copy to and go. Useful with combos and lists were you have an index, a key and a value for data purposes."), 2, 2);

  insertGroup(Group::Matrix, "Matrix", "matrix");
  insertInternal(Matrix::fromString, "fromString(TQString matrix, TQString String, bool With-Row-Keys, bool With-Col-Keys)", 
    i18n("Create a 2D array with zero based integer keys. Rows seperated with returns or \\n and columns with tabs or \\t. You can then read and alter values with \"name[0][1]\".<br><b>NOTE: Watch keys!</b> The row and column keys when set to true will read respectively the first row and first column as headings. If for instance you set one where there is no column or row heading to read it will read data, and if the data is not unique you will have missing columns or rows as well as addressing not working."), 2, 4);
  insertInternal(Matrix::toString, "toString(TQString matrix, bool RowHeadings, bool ColHeadings)",
    i18n("Convert 2D array to string, optionaly with row and column headings. If written without values set it will default to no headings."), 1, 3);
  insertInternal(Matrix::rows, "rows(TQString matrix)",
    i18n("Return the number of rows in the matrix"), 1);
  insertInternal(Matrix::columns, "columns(TQString matrix)",
    i18n("Return the number of columns in the matrix"), 1);
  insertInternal(Matrix::clear, "clear(TQString matrix)",
    i18n("Clear the entire matrix"), 1);
  insertInternal(Matrix::rowToArray, "rowToArray(TQString matrix, TQString Row, TQString Array, bool Clear-First, bool Indexed)",
    i18n("Convert row to array. Useful break out rows of data to work with. If you want to avoid spurious data Clear-First will wipe the array before filling it. If you choose indexed it will use a zero based index. Otherwise it will use the column keys."), 3, 5);
  insertInternal(Matrix::columnToArray, "columnToArray(TQString matrix, TQString Column, TQString Array)",
    i18n("Copy a column of a Matrix to an array and optionally clear array first to avoid spurious data in loops"), 3);
  insertInternal(Matrix::columnToIndexedArray, "columnToIndexedArray(TQString matrix, TQString Column, TQString Array)",
    i18n("Copy a column of a Matrix to an indexed array"), 3);
  insertInternal(Matrix::rowKeys, "rowKeys(TQString Matrix, TQString Seperator)",
    i18n("Return the row keys from the matrix. Separator defaults to [tab] \"\\t\" if left empty"), 1, 2);
  insertInternal(Matrix::columnKeys, "columnKeys(TQString Matrix, TQString Seperator)",
    i18n("Return the column keys from the matrix. Separator defaults to [tab] \"\\t\" if left empty"), 1, 2);
  insertInternal(Matrix::addRow, "addRow(TQString Matrix, TQString RowKey, TQString data)",
    i18n("Add a row to the matrix. Specifiy the row key and format the data as column key [tab] column value on each line using key\\tval\\nkey\\tval format"), 3);
  insertInternal(Matrix::removeRow, "removeRow(TQString Matrix, TQString RowKey)",
    i18n("Remove a row from the matrix by key name. Returns true if key is found."), 2);
  insertInternal(Matrix::removeColumn, "removeColumn(TQString Matrix, TQString ColKey)",
    i18n("Remove a column from the matrix by key name. Returns true if key is found."), 2);
  insertInternal(Matrix::findRow, "findRow(TQString Matrix, TQString Col-Key, TQString Col-Value, int Iteration)",
    i18n("Find the row key that matches a column value. Use this for unique key searches. Iteration may be omitted and the default is to return the first instance. In a loop it will return sequential finds until there are no more, in which case it returns null."), 3, 4);

  insertGroup(Group::String, "String", "str");
  insert(String::length, "length(TQString string)", 
    i18n("Returns number of chars in the string."), 1);
  insert(String::contains, "contains(TQString string, TQString substring)", 
    i18n("Checks if the the string contains the given substring."), 2);
  insert(String::find, "find(TQString string, TQString sought, int index)", 
    i18n("Returns the position of a substring in the string, or -1 if it is not found."), 2);
  insert(String::findRev, "findRev(TQString string, TQString sought, int index)", 
    i18n("Returns the position of a substring in the string, or -1 if it is not found. String is searched backwards"), 2);
  insertInternal(String::count, "count(TQString String, TQString substring)",
    i18n("Returns the count of a given substring in the given string."), 2);
  insert(String::left, "left(TQString string, int n)", 
    i18n("Returns the first <i>n</i> chars of the string."), 2);
  insert(String::right, "right(TQString string, int n)", 
    i18n("Returns the last <i>n</i> chars of the string."), 2);
  insert(String::mid, "mid(TQString string, int start, int n)", 
    i18n("Returns <i>n</i> chars of the string, starting from <i>start</i>."), 3);
  insert(String::remove, "remove(TQString string, TQString substring)", 
    i18n("Removes all occurrences of given substring."), 2);
  insert(String::replace, "replace(TQString string, TQString substring, TQString replacement)", 
    i18n("Replaces all occurrences of the given substring with the given replacement."), 3);
  insert(String::upper, "upper(TQString string)", 
    i18n("Converts the string to uppercase."), 1);
  insert(String::lower, "lower(TQString string)", 
    i18n("Converts the string to lowercase."), 1);
  insert(String::compare, "compare(TQString string1, TQString string2)", 
    i18n("Compares two strings. Returns 0 if they are equal, "
    "-1 if the first one is lower, 1 if the first one is higher"), 2);
  insert(String::isEmpty, "isEmpty(TQString string)", 
    i18n("Checks if the string is empty."), 1);
  insert(String::isNumber, "isNumber(TQString string)", 
    i18n("Checks if the string is a valid number."), 1);
  insert(String::section, "section(TQString string, TQString separator, int index)", 
    i18n("Returns given section of a string."), 1);
  insert(String::args, "args(TQString string, TQString arg1, TQString arg2, TQString arg3)", 
    i18n("Returns the given string with %1, %2, %3 replaced with <i>arg1</i>, <i>arg2</i>, <i>arg3</i> accordingly."), 2);
  insert(String::round, "round(TQString Number, int Digits)", 
    i18n("Round a floating point number by x digits."), 2);
  insertInternal(String::sort, "sort(TQString String, TQString Separator)", 
    i18n("Sort a string list. Only first paramter is required. Default separator is a newline."), 1, 2);
  insertInternal(String::trim, "trim(TQString String)", 
    i18n("Strips white space from beginning and end of string."), 1);
  insertInternal(String::padLeft, "padLeft(TQString String, int Length, TQString Pad)", 
    i18n("Pads the string to the total length indicated. if no pad character is given spaces will be used. Try this with 0 on integer sequences and read them with str_toint."), 1, 2);
  insertInternal(String::padRight, "padRight(TQString String, int Length, TQString Pad)", 
    i18n("Pads the string to the total length indicated. if no pad character is given spaces will be used."), 1, 2);

  insertInternal(String::toInt, "toint(TQString string, TQString default)",
    i18n("Convert a string to an integer. If not possible use the default value"), 1, 2);
  insertInternal(String::toDouble, "todouble(TQString string, TQString default)",
    i18n("Convert a string to a double precision floating point value. If not possible use the default value"), 1, 2);

  insertGroup(Group::File, "File", "file");
  insert(File::read, "read(TQString file)", 
    i18n("Returns content of given file."), 1);
  insert(File::write, "write(TQString file, TQString string)", 
    i18n("Writes given string to a file."), 2);
  insert(File::append, "append(TQString file, TQString string)", 
    i18n("Appends given string to the end of a file."), 2);
  insert(File::exists, "exists(TQString file)", 
    i18n("Checks to see if file exists."), 1);
  
  insertGroup(Group::Input, "Input", "input");
  insert(Input::color, "color(TQString defaultColor)", i18n("Shows color dialog. Returns color in #RRGGBB format. Defaults to the parameter, if specified."), 0, 1);
  insert(Input::text, "text(TQString caption, TQString label, TQString default)", 
         i18n("Shows text selection dialog. Returns entered text."), 2);
  insert(Input::password, "password(TQString caption, TQString password)", 
         i18n("Shows a dialog asking user for password and returns it."), 1);
  insert(Input::value, "value(TQString caption, TQString label, int value, int min, int max, int step)", 
         i18n("Shows value selection dialog. Returns entered value."), 5);
  insert(Input::valueDouble, "double(TQString caption, TQString label, double value, double min, double max, double step)", 
         i18n("Shows float value selection dialog. Returns entered value."), 6);
  insert(Input::openfile, "openfile(TQString startdir, TQString filter, TQString caption)", 
         i18n("Shows existing file selection dialog. Returns selected file."), 0);
  insert(Input::savefile, "savefile(TQString startdir, TQString filter, TQString caption)", 
         i18n("Shows save file selection dialog. Returns selected file."), 0);
  insert(Input::directory, "directory(TQString startdir, TQString filter, TQString caption)", 
         i18n("Shows directory selection dialog. Returns selected directory."), 0);
  insert(Input::openfiles, "openfiles(TQString startdir, TQString filter, TQString caption)", 
         i18n("Shows multiple files selection dialog. Returns EOL-separated list of selected files."), 0);
  
  insertGroup(Group::Message, "Message", "message");
  insert(Message::info, "info(TQString text, TQString caption)", 
         i18n("Shows an information dialog. Returns true when clicked so you can check for user response."), 1);
  insert(Message::error, "error(TQString text, TQString caption)", 
         i18n("Shows an error dialog. Returns true when clicked so you can check for user response."), 1);
  insert(Message::warning, "warning(TQString text, TQString caption, TQString button1, TQString button2, TQString button3)",
         i18n("Shows a warning dialog with up to three buttons. Returns number of selected button."), 1);
  insert(Message::question, "question(TQString text, TQString caption, TQString button1, TQString button2, TQString button3)",
         i18n("Shows a question dialog with up to three buttons. Returns number of selected button."), 1);
  
}

TQMap<int, TQMap<int, SpecialFunction> > SpecialInformation::m_specials;
TQMap<TQString, int> SpecialInformation::m_groups;
TQMap<TQString, TQString> SpecialInformation::m_parserGroups;
TQMap<int, TQMap<TQString, int> > SpecialInformation::m_functions;
TQMap<int, TQMap<TQString, int> > SpecialInformation::m_aliases;
int SpecialInformation::m_defaultGroup;

