/**
Create_Constructor.bsh - a BeanShell macro for the jEdit text editor  that 
creates a constructor containing the selected variables.  This code has the 
similar limitations as Get_Class_Name; it merely looks backwards for the nearest 
occurance of the keyword 'class," etc.

Copyright (C)  2004 Thomas Galvin - software@thomas-galvin.com

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 any later version.

This program 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.
*/

//Localization
final static String UnevenNumberMessage = jEdit.getProperty("macro.rs.CreateConstructor.UnevenNumber.message", "Uneven number of type names and variables.");
final static String NotEditableMessage = jEdit.getProperty("macro.rs.general.ErrorNotEditableDialog.message", "Buffer is not editable");
    
// Process
boolean JAVA_MODE = buffer.getMode().getName().toLowerCase().equals("java");
String UNDEFINED = "UNKNOWN_CLASS";

void setCaret(int selectionStart, int selectionEnd)
{
  textArea.setCaretPosition(selectionStart);
  textArea.moveCaretPosition(selectionEnd);
}

String getClassName()
{
  int selectionStart;
  int selectionEnd;
  if(textArea.getSelection().length != 0){  // if there are selections exists
      selectionStart = textArea.getSelection(0).getStart();
      selectionEnd = textArea.getSelection(0).getEnd();
  }
  else{		// if no selection
      selectionStart = textArea.getCaretPosition();
      selectionEnd = textArea.getCaretPosition();
  }
  
  String text = textArea.getText();
  int index = text.lastIndexOf("class", selectionStart);
  if(index != -1)
  {
    textArea.setCaretPosition(index);
    int lineNumber = textArea.getCaretLine();
    int lineEnd = textArea.getLineEndOffset(lineNumber);
    String lineText = text.substring(index, lineEnd);
    
    StringTokenizer tokenizer = new StringTokenizer(lineText);
    tokenizer.nextToken(); //eat "class"
    if(tokenizer.hasMoreTokens())
    {
      setCaret(selectionStart, selectionEnd);
      return tokenizer.nextToken();
    }
  }
  setCaret(selectionStart, selectionEnd);
  
  String fileClassName = buffer.getName();
  int index = fileClassName.lastIndexOf('.');
  if(index != -1)
  {
    fileClassName = fileClassName.substring(0, index);
    if(fileClassName.toLowerCase().indexOf("untitled") == -1)
    {
      return fileClassName;
    }
  }
  
  return UNDEFINED;
}

public String createJavaConstructor(String className, String[] typeNames, String[] variableNames)
{
  if(typeNames.length != variableNames.length)
  {
    Macro.message(view, UnevenNumberMessage);
    return "";
  }
  
  String args = "";
  String body = "";
  
  for(int i = 0; i < typeNames.length; i++)
  {
    args += typeNames[i] + " " + variableNames[i];
    if(i+1 < typeNames.length)
    {
      args += ",\n";
    }
    
    body += "this." + variableNames[i] + " = " + variableNames[i] + ";\n";
  }
  
  String code = 
  "/**\n" + "Basic constructor for " + className + "\n*/\n" + 
  "public " + className + 
  "(" +  args + ")" + "\n" + 
  "{" + "\n" + 
    body + 
  "}" + "\n";
  
  return code;
}

public String createCppConstructor(String className, String[] typeNames, String[] variableNames)
{
  if(typeNames.length != variableNames.length)
  {
    Macro.message(view, UnevenNumberMessage);
    return "";
  }
  
  String args = "";
  String body = "";
  
  for(int i = 0; i < typeNames.length; i++)
  {
    String setVariable = variableNames[i] + "Value";
    
    args += typeNames[i] + "& " + setVariable;
    body += variableNames[i] + "(" + setVariable + ")";
    
    if(i+1 < typeNames.length)
    {
      args += ",\n";
      body += ",";
    }
    
    body += "\n";
  }
  
  String code = 
  "/*\n" + "Basic constructor for " + className + "\n*/\n" + 
  className + "::" + className +  
  "(" +  args + ")" + "\n" + 
  "throw()\n" + 
  " : " + body + 
  "{" + "\n" + 
  "}" + "\n";
  
  return code;
}

void parseSelection()
{
  int selectionStart;
  int selectionEnd;
  if(textArea.getSelection().length != 0){  // if there are selections exists
      selectionStart = textArea.getSelection(0).getStart();
      selectionEnd = textArea.getSelection(0).getEnd();
  }
  else{		// if no selection
      selectionStart = textArea.getCaretPosition();
      selectionEnd = textArea.getCaretPosition();
  }
  
  textArea.setCaretPosition(selectionStart);
  int startLine = textArea.getCaretLine();
  
  textArea.setCaretPosition(selectionEnd);
  int endLine = textArea.getCaretLine();
  
  Vector typeNames = new Vector();
  Vector variableNames = new Vector();
  
  for(int i = startLine; i <= endLine; i++)
  {
    String lineText = textArea.getLineText(i);
    if( lineText != null && !lineText.equals("") )
    {
      lineText = lineText.trim();
      if( lineText.endsWith(";") )
      {
        lineText = lineText.substring( 0, lineText.length() -1 );
      }
      
      StringTokenizer tokenizer = new StringTokenizer(lineText);
      int tokenCount = tokenizer.countTokens();
      if(tokenCount >= 2)
      {
        int numGarbage = tokenCount - 2;
        for (int i = 0; i < numGarbage; i++)
        {
          tokenizer.nextToken();
        }
        
        String type = tokenizer.nextToken();
        String variable = tokenizer.nextToken();
        
        if(type != null &&
           type.compareTo("") != 0 &&
           variable != null &&
           variable.compareTo("") != 0 )
        {
          typeNames.add(type);
          variableNames.add(variable);
        }
      }
    }
  }
  
  int size = typeNames.size();
  String [] types = new String[size];
  String [] variables = new String[size];
  
  for(int i = 0; i < size; i++)
  {
    types[i] = typeNames.get(i).toString();
    variables[i] = variableNames.get(i).toString();
  }
  
  String code = "\n";
  if(JAVA_MODE)
  {
    code += createJavaConstructor(getClassName(), types, variables);
    textArea.setCaretPosition(selectionEnd);
    textArea.setSelectedText(code);
  }
  else
  {
    code += createCppConstructor(getClassName(), types, variables);
    textArea.setCaretPosition(selectionEnd);
    textArea.setSelectedText(code);
  }
  
  textArea.setCaretPosition(selectionEnd);
  textArea.moveCaretPosition(selectionEnd + code.length(), true);
  textArea.indentSelectedLines();
}

	parseSelection();
