/* Copyright (C) 1999,2000,2002 by Peter Eastman

   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.

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

package artofillusion.ui;

import artofillusion.*;
import buoy.widget.*;
import buoy.event.*;
import java.util.*;


/** Description of an item in the itemList and "object" of the MenuTreeElement.
  Each item in 
*/

public class MenuDescription
{
  public boolean menu;
  public String internalName;
  public Shortcut shortcut;
  public boolean useDefaultShortcut;
  public String labelText;
  
  public MenuDescription()
  {
    useDefaultShortcut = true;
    internalName = "";
    // labelText = "";
  }

  public MenuDescription(String descText, boolean menu)
  {
    this();
    setDescText(descText);
    this.menu = menu;
  }

  public MenuDescription(String descText)
  {
    this(descText, false);
  }
  

  /** For saving a label in a *.menu file, spaces are replaced by '\s'
    and '\' is replaced by '\\'. A null object is quoted as '\0',
    an empty string as '\e'.<BR>
    The returned string has at least length 1 and doesn't contain
    spaces.
   */
  public static String quote(String l)
  {
    if (l == null)
      return "\\0";
    else if ("".equals(l))
      return "\\e";
    
    StringBuffer result = new StringBuffer();

    for(int i = 0; i < l.length(); ++i)
    {
      if (l.charAt(i) == ' ')
        result.append("\\s");
      else if (l.charAt(i) == '\\')
        result.append("\\\\");
      else
        result.append(l.charAt(i));
    }
    return result.toString();
  }

  /** Opposite of {@link #quote(String)}. */

  public static String unquote(String l)
  {
    if ("\\0".equals(l))
      return null;
    else if ("\\e".equals(l))
      return "";
    
    StringBuffer result = new StringBuffer();

    for(int i = 0; i < l.length(); ++i)
    {
      if (l.charAt(i) == '\\')
      {
        i++;
        if (l.charAt(i) == 's')
          result.append(" ");
        else if (l.charAt(i) == '\\')
          result.append("\\");
      }
      else
        result.append(l.charAt(i));
    }
    return result.toString();
  }

  /** Get the text token which describes the menu shortcut setting of
    the described menu item. Quoting is done automatically.<BR>
    The returned string has at least length 1 and doesn't contain
    spaces. The three possibilities 'no shortcut', 'default shortcut' or
    a custom shortcut can be encoded.
   */
  
  public String getShortcutToken()
  {
    if (useDefaultShortcut)
      return quote(null);   // Default shortcut
    else
      if (shortcut == null)
        return quote("");   // No shortcut at all.
      else
      {
        if ((shortcut.getModifiers() & Shortcut.SHIFT_MASK) != 0)
          return quote("S"+shortcut.getKeyCode());
        else
          return quote(""+shortcut.getKeyCode());
      }
  }
  
  /** Set the text token which describes the menu shortcut setting of
    the described menu item and set the shortcut.
    Unquoting is done automatically. */
  
  public void setShortcutToken(String shortcutstring)
  {
    String shstr = unquote(shortcutstring);

    if (shstr == null)
    {                    // Default shortcut
      useDefaultShortcut = true;
      shortcut = null;
      return;
    }
    else
      useDefaultShortcut = false;      
      
    if ("".equals(shstr))
      shortcut = null;     // No shortcut at all.
    else
    {
      int keycode;
      boolean usesshift = false;

      if (shstr.charAt(0) == 'S')
      {
        usesshift = true;
        shstr = shstr.substring(1);
      }
      keycode = Integer.decode(shstr).intValue();
      
      shortcut = new Shortcut(keycode, Shortcut.DEFAULT_MASK | (usesshift ? Shortcut.SHIFT_MASK : 0));
    }
  }
  
  /** Returns a line of text which describes this menu item. Such lines are
    written to and read from the *.menu files. */
  
  public String getDescText()
  {
//    if (! "".equals(labelText))
    return quote(internalName)+" "+getShortcutToken()+" "+quote(labelText);
//    else
//      return quote(internalName);
  }

  /** Parse a description line and set the fields appropriate. */  
  public void setDescText(String descText)
  {
    String[] pieces = Utilities.breakLine(descText);
    internalName = unquote(pieces[0]);
    if (pieces.length > 1)
      setShortcutToken(pieces[1]);
    else
      useDefaultShortcut = true;      
      
    if (pieces.length > 2)
      labelText = unquote(pieces[2]);
    else
      labelText = null;   // Means use default
  }
  
  public boolean equals(Object o)
  {
    if (!(o instanceof MenuDescription))
      return false;

    MenuDescription d = (MenuDescription)o;

    return d.internalName.equals(internalName) && (d.menu == menu);
  }

  /** Returns a string which is shown in the tree and the menu item list. */
  public String getPresentableString()
  {
    return getLabel()+" ("+internalName+")";
  }
  
  /** Returns the label of the item. If labelText is equal "" or == null
    the default label is returned. */
  
  public String getLabel()
  {
    if (labelText == null || "".equals(labelText))
      return LayoutWindow.getDefaultMenuLabel(internalName);
    else
      return labelText;
  }
  
  /** Returns the default MenuShortcut of the item. If null is returned,
    the item has no shortcut.
   */
  
  public Shortcut getDefaultMenuShortcut()
  {
    if (menu)
      return null;   // Submenus never have shortcuts.
    
    return Translate.getShortcut(internalName);
  }
  
  /** Returns the MenuShortcut of the item. If useDefaultShortcut is true,
    the default shortcut is returned. If null is returned, the item has
    no shortcut.
   */
  public Shortcut getMenuShortcut()
  {
    if (menu)
      return null;   // Submenus never have shortcuts.
    if (useDefaultShortcut)
      return getDefaultMenuShortcut();
    else
      return shortcut;
  }
  
  /** Returns a textual description of the shortcut sh for user presentation.
    This may be the default or an own shortcut.
    May be an empty string if no shortcut is defined. */
  //(MB) Missing in buoy
  
  public static String getShortcutDescription(Shortcut sh)
  {
    if (sh == null)
      return "";
    
    return sh.getKeyStroke().toString();  // TODO(MB) Better, localized, method
  }
  
  /** Test, if 2 Shortcuts are equal. */
  //(MB) Missing in buoy
  
  public static boolean shortcutEquality(Shortcut sh1, Shortcut sh2)
  {
    if ((sh1 == null) || (sh2 == null))
      return false;
    
    return getShortcutDescription(sh1).equals(getShortcutDescription(sh2));
  }
  
  /** Set label and shortcut of menuitem as defined in the description.
    The internal name (= action command) is <b>not</b> set. */
  
  public void applyTo(MenuWidget menuitem)
  {
    if (menuitem instanceof BMenu)   //(MB) Workaround for little buoy problem
      ((BMenu)menuitem).setText(getLabel());
    else if (menuitem instanceof BMenuItem)
      ((BMenuItem)menuitem).setText(getLabel());
    
    Shortcut shcut = getMenuShortcut();
    if (menuitem instanceof BMenuItem)
    {
      if (shcut == null)
        ((BMenuItem)menuitem).setShortcut(null);    //(MB) ?  .deleteShortcut();
      else
        ((BMenuItem)menuitem).setShortcut(shcut);
    }
  }
}

