/*
 * jNPad v0.3 - jNPad's an Simple Text Editor written in Java
 *
 * Copyright (C) 2014-2017  rgs
 *
 * Require JDK 1.6 (or later)
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 *
 * Info, Questions, Suggestions & Bugs Report to rgsevero@gmail.com
 */

package jnpad.filebrowser;

import java.awt.Color;
import java.awt.Font;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import jnpad.config.Config;
import jnpad.util.Utilities;

/**
 * The Class FileBrowserObject.
 *
 * @version 0.3
 * @since jNPad 0.1
 */
public class FileBrowserObject implements Comparable<FileBrowserObject> {
  /** executable formats */
  @SuppressWarnings("nls")
  private static final String[] EXEC = {"cmd", "exe", "com", "btm", "bat", "sh", "csh"};

  /** archives or compressed */
  @SuppressWarnings("nls")
  private static final String[] COMP = {"tar", "tgz", "arj", "taz", "lzh", "lzma", "tlz", "txz"
      , "zip", "z", "Z", "dz", "gz", "lz", "xz", "bz2", "bz", "tbz", "tbz2", "tz", "deb", "rpm",
      "jar", "war", "ear", "sar", "rar", "ace", "zoo", "cpio", "7z", "rz", "pea"};

  /** image formats */
  @SuppressWarnings("nls")
  private static final String[] IMAGE = {"jpg", "jpeg", "gif", "bmp", "pbm", "pgm", "ppm", "tga",
      "xbm", "xpm", "tif", "tiff", "png", "svg", "svgz", "mng", "pcx", "mov", "mpg", "mpeg",
      "m2v", "mkv", "webm", "ogm", "mp4", "m4v", "mp4v", "vob", "qt", "nuv", "wmv", "asf",
      "rm", "rmvb", "flc", "avi", "fli", "flv", "gl", "dl", "xcf", "xwd", "yuv", "cgm", "emf", "ico",
      // http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
      "axv", "anx", "ogv", "ogx"};

  /** audio formats */
  @SuppressWarnings("nls")
  private static final String[] AUDIO = {"aac", "au", "flac", "mid", "midi", "mka", "mp3",
      "mpc", "ogg", "ra", "wav",
      // http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
      "axa", "oga", "spx", "xspf"};

  static boolean                        colors_enabled;
  static Font                           font_normal;
  static Font                           font_bold;
  static Font                           font_device;
  static Color                          fg_dir;
  static Color                          fg_exec;
  static Color                          fg_link;
  static Color                          fg_comp;
  static Color                          fg_image;
  static Color                          fg_audio;

  private static final String           SPACE       = "  ";                                                                      //$NON-NLS-1$
  private static final String           DIR         = "     <DIR>";                                                              //$NON-NLS-1$
  private static final int              DIR_LENGTH  = DIR.length();
  private static final SimpleDateFormat DATE_FOTMAT = new SimpleDateFormat("MMM dd yyyy HH:mm"); //$NON-NLS-1$

  private Font                          font        = Config.BROWSER_NORMAL_FONT.getValue();
  private Color                         fg          = Config.TEXT_FOREGROUND.getValue();

  private File                          file;
  private String                        linkedTo;
  private String                        line;

  static {
    updateDirColors();
  }

  /**
   * Instantiates a new file browser object.
   * 
   * @param file the file
   */
  public FileBrowserObject(File file) {
    this(file, false);
  }

  /**
   * Instantiates a new file browser object.
   * 
   * @param file the file
   * @param file_system_root the file_system_root
   */
  public FileBrowserObject(File file, boolean file_system_root) {
    this.file = file;

    if (file_system_root) {
      font = font_device;
      line = getName();
    }
    else {
      if (file.isDirectory()) {
        font = font_bold;
        fg = fg_dir;
      }
      else if (file.isFile()) {
        String name = file.getName();
        if (Utilities.isFileExtension(name, EXEC)) {
          font = font_normal;
          fg = fg_exec;
        }
        else if (Utilities.isFileExtension(name, COMP)) {
          font = font_normal;
          fg = fg_comp;
        }
        else if (Utilities.isFileExtension(name, IMAGE)) {
          font = font_normal;
          fg = fg_image;
        }
        else if (Utilities.isFileExtension(name, AUDIO)) {
          font = font_normal;
          fg = fg_audio;
        }
        else if (file.canExecute()) {
          font = font_normal;
          fg = fg_exec;
        }
      }

      try {
        String cp = file.getCanonicalPath();
        String ap = file.getAbsolutePath();
        if (!cp.equals(ap)) {
          linkedTo = cp;
          font = font_bold;
          fg = fg_link;
        }
      }
      catch (IOException e) {
        //ignore
      }
      
      StringBuilder sb = new StringBuilder();
      sb.append(getFilePermissions()).append(SPACE);
      //sb.append(getOwner()).append(SPACE);
      //sb.append(getGroup()).append(SPACE);
      sb.append(getSize()).append(SPACE);
      sb.append(getDateTime()).append(SPACE);
      sb.append(getName());
      if (linkedTo != null) {
        sb.append(" -> "); //$NON-NLS-1$
        sb.append(linkedTo);
      }
      if (Config.BROWSER_CLASSIFY.getValue()) {
        if (file.isDirectory()) {
          sb.append("/"); //$NON-NLS-1$
        }
        else if (file.canExecute()) {
          sb.append("*"); //$NON-NLS-1$
        }
      }
      line = sb.toString();
    }
  }

  /**
   * Compare to.
   *
   * @param other the other
   * @return int
   * @see java.lang.Comparable#compareTo(java.lang.Object)
   */
  @Override
  public int compareTo(FileBrowserObject other) {
    return getName().compareTo(other.getName());
  }

  /**
   * @param obj Object
   * @return boolean 
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object obj) {
      return obj == this || obj instanceof FileBrowserObject && getName().equals(((FileBrowserObject) obj).getName());
  }

  /**
   * @return int
   * @see java.lang.Object#hashCode()
   */
  @Override
  public int hashCode() {
    return getName().hashCode();
  }

  /**
   * Gets the file.
   *
   * @return the file
   */
  public File getFile() {
    return file;
  }

  /**
   * Gets the name.
   * 
   * @return the name
   */
  public String getName() {
    String name = file.getName();
    if (Utilities.isEmptyString(name)) {
      name = file.getPath();
    }
    return name;
  }

  /**
   * Gets the line.
   *
   * @return the line
   */
  public String getLine() {
    return line;
  }
  
  /**
   * Gets the font.
   *
   * @return the font
   */
  public Font getFont() {
    return font;
  }

  /**
   * Gets the foreground.
   *
   * @return the foreground
   */
  public Color getForeground() {
    return fg;
  }
  
  /**
   * Gets the file permissions.
   *
   * @return the file permissions
   */
  public String getFilePermissions() {
    final boolean r = file.canRead();
    final boolean w = file.canWrite();
    final boolean x = file.canExecute();
    return (file.isDirectory() ? "d" : "-") + //$NON-NLS-1$ //$NON-NLS-2$
      //owner
      (r ? 'r' : '-') +
      (w ? 'w' : '-') +
      (x ? 'x' : '-') /*+
      //group
      (r ? '.' : '-') +
      (w ? '.' : '-') +
      (x ? '.' : '-') +
      //other
      (r ? '.' : '-') +
      (w ? '.' : '-') +
      (x ? '.' : '-')*/
    ;
  }

  /**
   * Gets the owner.
   *
   * @return the owner
   */
  public String getOwner() {
    //TODO
    return Utilities.fixSizeString(7, true, "?"); //$NON-NLS-1$
  }

  /**
   * Gets the group.
   *
   * @return the group
   */
  public String getGroup() {
    //TODO
    return Utilities.fixSizeString(7, true, "?"); //$NON-NLS-1$
  }

  /**
   * Gets the size.
   *
   * @return the size
   */
  public String getSize() {
    if (file.isDirectory()) {
      return DIR;
    }
    
    long bytes = file.length();
    
    String sizeString;
    
    if(Config.BROWSER_HUMAN_READABLE.getValue()) {
      final String units = "BKMG"; //$NON-NLS-1$
      int unit = 0;
      int fraction = 0;
      while (bytes > 1000 && (unit + 1) < units.length()) {
        bytes /= 100;
        fraction = (int) (bytes % 10);
        bytes /= 10;
        unit++;
      }
      if (bytes < 10) {
        sizeString = bytes + "." + fraction + units.charAt(unit); //$NON-NLS-1$
      }
      else {
        sizeString = (bytes < 100 ? Utilities.SPACE_STRING : Utilities.EMPTY_STRING) + bytes + units.charAt(unit);
      }
    }
    else {
      sizeString = String.valueOf(bytes);
    }
    
    return Utilities.fixSizeString(DIR_LENGTH, false, sizeString);
  }

  /**
   * Gets the date time.
   *
   * @return the date time
   */
  public String getDateTime() {
    synchronized (DATE_FOTMAT) { // Keep FindBugs happy
      return DATE_FOTMAT.format(new Date(file.lastModified()));
    }
  }
  
  /**
   * To string.
   *
   * @return String
   */
  @Override
  public String toString() {
    return getName();
  }
  
  /**
   * Update dir colors.
   */
  public static void updateDirColors() {
    font_normal = Config.BROWSER_NORMAL_FONT.getValue();
    font_bold   = Config.BROWSER_BOLD_FONT.getValue();
    font_device = Config.BROWSER_DEVICE_FONT.getValue();

    colors_enabled = Config.BROWSER_COLORS_ENABLED.getValue();

    if (colors_enabled) {
      fg_dir   = Config.BROWSER_DIR_FOREGROUND.getValue();
      fg_exec  = Config.BROWSER_EXEC_FOREGROUND.getValue();
      fg_link  = Config.BROWSER_LINK_FOREGROUND.getValue();
      fg_comp  = Config.BROWSER_COMP_FOREGROUND.getValue();
      fg_image = Config.BROWSER_IMAGE_FOREGROUND.getValue();
      fg_audio = Config.BROWSER_AUDIO_FOREGROUND.getValue();
    }
    else {
      fg_dir = fg_exec = fg_link = fg_comp = fg_image = fg_audio = Config.TEXT_FOREGROUND.getValue();
    }
  }
  
}
