import java.awt.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.File;

/**
 * Class MyList
 * @version        0.1 Feb 1997 
 * @author         Ebele Nicolas, Mallet Frederic
 * date : 22/03/97  19:31
 */

public class MyList extends Panel {
  protected List list;
  protected Scrollbar sb;
  private boolean mult_sel = false;
  protected int max_it = 0;
  private Image IFol, IUp, IDef;
  private Vector ext;    // Garde les extensions
  private Hashtable im;  // garde les images
  private String ImPath; // Chemin du repertoire contenant les images
  protected String Info=" ";   // Lignes contenants de l'information

/**
 * Construit une MyList
 * java.awt.List avec en plus le traitement des couleurs et
 * images.
 */
  MyList() {
    ClassName = "MyList";
    list = new List();
    setLayout(null);
    add(sb = new Scrollbar());
    Initialise();
    setBackground(BackGround);
    Toolkit tk = Toolkit.getDefaultToolkit();
    IFol = tk.getImage(ImPath+File.separatorChar+IconFolder);
    IUp = tk.getImage(ImPath+File.separatorChar+IconParent);
    IDef = tk.getImage(ImPath+File.separatorChar+IconDefault);
    im = new Hashtable();
    String tmp, id, value;
    int i;
    for (Enumeration en = ext.elements(); en.hasMoreElements(); ) {
      tmp = (String)en.nextElement();
      i = tmp.indexOf(Init.Affect);
      id = tmp.substring(0, i);
      value = tmp.substring(i+1, tmp.length());
      im.put(id.toLowerCase(), tk.getImage(ImPath+File.separatorChar+value));
      Init.println(ClassName, id+"="+value);
    }
  }

/**
 * construit une liste
 * @param multipleSelection si true, les selections multiples sont autorisėes
 */
  MyList(boolean multipleSelection) {
    this();
    list.setMultipleSelections(multipleSelection);
  }

// Lecture des parametres d'initialisation
  private void Initialise() {
    String param;

    param = (String)Init.get(ClassName, "Layout", "LINE_SIZE");
    LINE_SIZE = param==null?LINE_SIZE:Integer.parseInt(param);

    param = (String)Init.get(ClassName, "Layout", "TAB_SIZE");
    TAB_SIZE = param==null?TAB_SIZE:Integer.parseInt(param);

    param = (String)Init.get(ClassName, "Layout", "Info");
    Info = param==null?Info:param;

    param = (String)Init.get(ClassName, "Icons", "Folder");
    IconFolder = param==null?IconFolder:param;

    param = (String)Init.get(ClassName, "Icons", "ImagePath");
    ImPath = param==null?ImPath:param;

    param = (String)Init.get(ClassName, "Icons", "Parent");
    IconParent = param==null?IconParent:param;

    param = (String)Init.get(ClassName, "Icons", "Default");
    IconDefault = param==null?IconDefault:param;

// recuperation des couleurs
    getColor();

    ext = (Vector)Init.get(ClassName, "Extensions", "");
  }

/**
 * Recupere les parametres d'initialisation
 * concernant les couleurs
 */
  protected void getColor() {
    String param;

    param = (String)Init.get(ClassName, "Color", "background");
    BackGround = param==null?BackGround:Init.getColor(param);

    param = (String)Init.get(ClassName, "Color", "TextColor");
    TextColor = param==null?TextColor:Init.getColor(param);

    param = (String)Init.get(ClassName, "Color", "SelBackGround");
    SelBackGround = param==null?SelBackGround:Init.getColor(param);

    param = (String)Init.get(ClassName, "Color", "SelTextColor");
    SelTextColor = param==null?SelTextColor:Init.getColor(param);

    param = (String)Init.get(ClassName, "Color", "HighLine");
    HighLine = param==null?HighLine:Init.getColor(param);

    param = (String)Init.get(ClassName, "Color", "LowLine");
    LowLine = param==null?LowLine:Init.getColor(param);
  }

/**
 * Efface toutes les entrees de la liste
 */
  public void clear() {
    list.clear();
    sb.setValue(0);
    repaint();
  }

/**
 * @return tous les Items selectionnes
 */
  public String [] getSelectedItems() {
    return list.getSelectedItems();
  }

/**
 * Ajoute un Item a la fin de la liste
 * @param item texte de l'item a ajouter
 */
  public void addItem(String item) {
    list.addItem(item);
    repaint();
  }

/**
 * Ajoute un Item a la liste
 * @param item texte de l'item a ajouter
 * @param index position a laquelle il faut ajouter l'item
 */
  public void addItem(String item, int index) {
    list.addItem(item, index);
    repaint();
  }

/**
 * @return le nombre d'items contenus dans la liste
 */
  public int countItems() {
    return list.countItems();
  }

/**
 * gestion des clicks de souris
 * Si on selectionne une ligne, l'evenement LIST_SELECT est leve
 * Si on deselectionne une ligne, l'evenement LIST_DESELECT est leve
 * Si on double click une ligne, l'evenement ACTION_EVENT est leve
 * Dans tous les cas l'argument de l'evenement lance est une
 * String contenant le texte de la ligne concernee.
 * @return true tous les evenements sont captures
 */
  public boolean mouseDown(Event ev, int x, int y) {
    int pos=sb.getValue()+y/LINE_SIZE;
    if (pos>=countItems())
      return true;
    Init.println(ClassName, "Info:"+Info+":"+list.getItem(pos));
    if (ev.clickCount == 1) {
      if (list.isSelected(pos)) {
        list.deselect(pos);
        postEvent(new Event(this, Event.LIST_DESELECT, list.getItem(pos)));
      } else if (!list.getItem(pos).startsWith(Info)) {
        list.select(pos);
        postEvent(new Event(this, Event.LIST_SELECT, list.getItem(pos)));
      }
      repaint();
    } else if (ev.clickCount == 2)
      postEvent(new Event(this, Event.ACTION_EVENT, list.getItem(pos)));
    return true;
  }

/**
 * gestion des evenements concernant la scrollbar
 */
  public boolean handleEvent(Event ev) {
    switch (ev.id) {
    case Event.SCROLL_LINE_DOWN:
    case Event.SCROLL_LINE_UP:
    case Event.SCROLL_PAGE_DOWN:
    case Event.SCROLL_PAGE_UP:
    case Event.SCROLL_ABSOLUTE:
      repaint();
      break;
    default:
    }
    return super.handleEvent(ev);
  }

/**
 * Dessine eventuellement la scrollbar suivant qu'il y ait
 * trop de ligne ou non
 * @param view indexe de la premiere ligne vue
 * @param height hauteur en pixel de la zone
 * @param width largeur en pixel de la zone
 * @return abscisse du premier point utilisė par la Scrollbar
 */
  protected int drawScrollbar(int view, int height, int width) {
    if (max_it<countItems()) {
      sb.move(width-15, 0);
      sb.resize(20, height);
      sb.setValues(view, max_it, 0, countItems()-max_it);
      sb.show();
      return width-20;
    }
    sb.setValue(0);
    sb.hide();
    return width-5;
  }

/**
 * Dessine le cadre de la liste
 * @param g zone Graphics dans laquelle on va dessiner le cadre
 * @param height hauteur en pixel de la zone
 * @param width largeur en pixel de la zone
 */
  protected void drawBorder(Graphics g, int larg, int height) {
    g.setColor(HighLine);
    g.drawRect(0, 0, larg, height);
    g.drawLine(1, 1, larg-1, 1); g.drawLine(1, 1, 1, height-2);
    g.setColor(LowLine);
    g.drawLine(larg-1, 2, larg-1, height-2);
    g.drawLine(2, height-2, larg-1, height-2);
    g.drawLine(larg, 1, larg, height-1);
    g.drawLine(1, height-1, larg, height-1);
  }

  public void paint(Graphics g) {
    update(g);
  }

  public void update(Graphics g) {
    Dimension tmp = size();
    int height = tmp.height, larg;
    max_it = (height-4)/LINE_SIZE; // Nombre max d'items affichable

    int view=sb.getValue();
//Nettoie la zone autour de la ScrollBar
    g.setColor(BackGround);
    g.fillRect(tmp.width-25, 0, 10, height);
// Mise en place de la scrollbar
    larg = drawScrollbar(view, height, tmp.width);

// Dessin du cadre
    drawBorder(g, larg, height);

// Affichage du texte
    g.setColor(TextColor);
    boolean sel;
    String item;
    Font font = g.getFont();
    font = new Font(font.getName(), font.getStyle(), LINE_SIZE-8);
    g.setFont(font);
    FontMetrics fm = g.getFontMetrics(font);
    int i;
    for (i=view; (i-view)<max_it && i<list.countItems(); i++) {
      sel = list.isSelected(i);
      g.setColor(sel?SelBackGround:BackGround);
      g.fillRect(2, (i-view)*LINE_SIZE+2, larg-5, LINE_SIZE-3);
      item = drawIcon(g, list.getItem(i), i-view);
      g.setColor(sel?SelTextColor:TextColor);
      g.drawString(adapted(item, fm, larg-5-TAB_SIZE), TAB_SIZE, (i-view+1)*LINE_SIZE-5);
    }
    g.setColor(BackGround);
    for (; (i-view)<max_it; i++)
      g.fillRect(2, (i-view)*LINE_SIZE+2, larg-5, LINE_SIZE-3);
  }

/**
 * adapte la longueur d'une chaine pour qu'elle puisse etre
 * affichee dans la liste sans deborder
 * @param t chaine a afficher
 * @param fm FontMetrics de la police a utiliser
 * @param larg largeur disponible dans la zone
 * @return la chaine avec une longueur adaptee
 */
  protected String adapted(String t, FontMetrics fm, int larg) {
    for (int l=t.length(); fm.stringWidth(t)>larg; l--)
      t= t.substring(0, l-1);
    return t;
  }

// Dessine les icones correspondants aux fichiers representes
// par text a la position pos dans la liste
  private String drawIcon(Graphics g, String text, int pos) {
    // Si c'est '..'
    if (text.equals("..")) {
      g.drawImage(IUp, 3, pos*LINE_SIZE+3, TAB_SIZE-5, LINE_SIZE-5, this);
      return text;
    }

    Init.println(ClassName, "drawIcon:"+text);
// On recupere l'extension du fichier
    int Long = text.length(), ind = text.lastIndexOf('.');
    String ext = text.substring(ind+1, (ind==-1)?Long-1:Long).toLowerCase();
    int extL = ext.length();
    
// Si c'est un repertoire on enleve le / de l'extension
    if (extL>0 && ext.charAt(extL-1) == File.separatorChar)	
      ext=ext.substring(0, --extL);
 
    Init.println(ClassName, "ext="+ext+" extL="+extL);  		   
    Image IIm = (ext != null && im!=null)?(Image)im.get(ext.toLowerCase()):null;
    // Si c'est un fichier avec une extension definie
    if (IIm != null && IIm.getHeight(this) != -1) {
      g.drawImage(IIm, 3, pos*LINE_SIZE+3, TAB_SIZE-5, LINE_SIZE-5, this);
      return
       text.substring(0, Long-(extL==Long?1:extL+1));
    }

    // C'est un repertoire
    if (text.charAt(Long-1) == File.separatorChar) {
      g.drawImage(IFol, 3, pos*LINE_SIZE+3, TAB_SIZE-5, LINE_SIZE-5, this);
      return text.substring(0, Long-((IFol.getHeight(this)==-1)?0:1));
    }

    // Image par dļfaut
    g.drawImage(IDef, 3, pos*LINE_SIZE+3, TAB_SIZE-5, LINE_SIZE-5, this);

// Dans tous les autres cas, on affiche l'icone par defaut

    return text;
  }

  protected String ClassName;

// Valeurs par defaut
// toutes ces valeur peuvent etre modifiees dans
// le fichier d'initialisation

/**
 * Largeur de la zone reservee a l'icone
 */
  protected int TAB_SIZE = 30;

/**
 * Hauteur de la ligne
 */
  protected int LINE_SIZE = 20;

  private String IconParent = "up.jpg";
  private String IconFolder = "menu.jpg";
  private String IconJpgGif = "jpggif.jpg";
  private String IconDefault = "default.jpg";

  protected Color BackGround = Color.white;
  protected Color TextColor = Color.black;
  protected Color SelTextColor = Color.white;
  protected Color SelBackGround = new Color(0, 0, 128);
  protected Color HighLine = Color.black;
  protected Color LowLine = new Color(190, 190, 190);
}
