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

import static jnpad.action.JNPadActions.ACTION_NAME_FILE_PROPERTIES;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

import jnpad.GUIUtilities;
import jnpad.JNPadBundle;
import jnpad.JNPadFrame;
import jnpad.action.JNPadActions.Group;
import jnpad.config.Accelerators;
import jnpad.config.Config;
import jnpad.text.Buffer;
import jnpad.ui.EdgeBorder;
import jnpad.ui.EscapableDialog;
import jnpad.ui.status.StatusDisplayable.StatusType;
import jnpad.util.Utilities;

/**
 * The Class FilePropertiesAction.
 *
 * @version 0.3
 * @since jNPad 0.1
 */
public final class FilePropertiesAction extends JNPadAction {
  /** UID */
  private static final long serialVersionUID = 7422016878882557088L;

  /**
   * Instantiates a new file properties action.
   *
   * @param jNPad the jNPpad's frame
   */
  public FilePropertiesAction(JNPadFrame jNPad) {
    super(jNPad,
          ACTION_NAME_FILE_PROPERTIES,
          Group.FILE,
          Accelerators.FILE_PROPERTIES, Utilities.EMPTY_STRING);
  }

  /**
   * Perform action.
   *
   * @see jnpad.action.JNPadAction#performAction()
   */
  @Override
  public void performAction() {
    Buffer buffer = jNPad.getActiveBuffer();
    if (buffer != null) {
      File file = new File(buffer.getFilePath());
      if (file.exists()) {
        new FilePropertiesDialog(jNPad, file);
      }
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/**
 * The Class FilePropertiesDialog.
 */
class FilePropertiesDialog extends EscapableDialog {
  JPanel                      contentPane;

  JPanel                      pnBackground       = new JPanel();
  JPanel                      pnProperties       = new JPanel();
  JPanel                      pnPropertiesNames  = new JPanel();
  JPanel                      pnPropertiesValues = new JPanel();

  JLabel                      lbFileName         = new JLabel();

  JPanel                      pnAttributes       = new JPanel();
  JPanel                      pnReadable         = new JPanel();
  JCheckBox                   cbReadable         = new JCheckBox();
  JLabel                      lbReadable         = new JLabel();
  JPanel                      pnWritable         = new JPanel();
  JCheckBox                   cbWritable         = new JCheckBox();
  JLabel                      lbWritable         = new JLabel();
  JPanel                      pnHidden           = new JPanel();
  JCheckBox                   cbHidden           = new JCheckBox();
  JLabel                      lbHidden           = new JLabel();

  JPanel                      pnClose            = new JPanel();
  JButton                     btClose            = new JButton();

  JLabel                      lbPath             = new JLabel();
  JLabel                      lbPathValue        = new JLabel();
  JLabel                      lbLines            = new JLabel();
  JLabel                      lbLinesValue       = new JLabel();
  JLabel                      lbEOL              = new JLabel();
  JLabel                      lbEOLValue         = new JLabel();
  JLabel                      lbEncoding         = new JLabel();
  JLabel                      lbEncodingValue    = new JLabel();
  JLabel                      lbSize             = new JLabel();
  JLabel                      lbSizeValue        = new JLabel();
  JLabel                      lbModified         = new JLabel();
  JLabel                      lbModifiedValue    = new JLabel();

  private File file;

  /** Logger */
  private static final Logger LOGGER             = Logger.getLogger(FilePropertiesDialog.class.getName());

  /** UID */
  private static final long   serialVersionUID   = 2275677877542023512L;
  
  /**
   * Instantiates a new file properties dialog.
   *
   * @param jNPad the jNPad's frame
   * @param file File
   */
  public FilePropertiesDialog(JNPadFrame jNPad, File file) {
    super(jNPad, ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".title"), file.getName()), true); //$NON-NLS-1$
    try {
      this.file = file;
      jbInit();
      pack();
      setLocationRelativeTo(jNPad);
      setVisible(true);
    }
    catch (Exception ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      jNPad.setStatus(StatusType.ERROR, "Error - ".concat(getTitle())); //$NON-NLS-1$
    }
  }

  /**
   * Component initialization.
   *
   * @throws Exception the exception
   */
  private void jbInit() throws Exception {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(new BorderLayout());
    contentPane.add(pnBackground, BorderLayout.NORTH);
    contentPane.add(pnClose, BorderLayout.SOUTH);

    init();

    pnBackground.setLayout(new BorderLayout());
    pnBackground.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
    pnBackground.add(lbFileName, BorderLayout.NORTH);
    pnBackground.add(pnProperties, BorderLayout.CENTER);
    pnBackground.add(pnAttributes, BorderLayout.SOUTH);

    lbFileName.setHorizontalAlignment(SwingConstants.CENTER);
    lbFileName.setBorder(new EdgeBorder(EdgeBorder.EDGE_BOTTOM));

    pnProperties.setLayout(new BorderLayout(5, 0));
    pnProperties.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
    pnProperties.add(pnPropertiesNames, BorderLayout.WEST);
    pnProperties.add(pnPropertiesValues, BorderLayout.CENTER);

    lbPath.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".path"))); //$NON-NLS-1$
    lbLines.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".lines"))); //$NON-NLS-1$
    lbEOL.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".eol"))); //$NON-NLS-1$
    lbEncoding.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".encoding"))); //$NON-NLS-1$
    lbSize.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".size"))); //$NON-NLS-1$
    lbModified.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".modified"))); //$NON-NLS-1$
    
    pnPropertiesNames.setLayout(new GridLayout(6, 1, 0, 5));
    pnPropertiesNames.add(lbPath, null);
    pnPropertiesNames.add(lbLines, null);
    pnPropertiesNames.add(lbEOL, null);
    pnPropertiesNames.add(lbEncoding, null);
    pnPropertiesNames.add(lbSize, null);
    pnPropertiesNames.add(lbModified, null);

    pnPropertiesValues.setLayout(new GridLayout(6, 1, 0, 5));
    pnPropertiesValues.add(lbPathValue, null);
    pnPropertiesValues.add(lbLinesValue, null);
    pnPropertiesValues.add(lbEOLValue, null);
    pnPropertiesValues.add(lbEncodingValue, null);
    pnPropertiesValues.add(lbSizeValue, null);
    pnPropertiesValues.add(lbModifiedValue, null);
    
    pnAttributes.setBorder(BorderFactory.createTitledBorder(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".attributes.title")))); //$NON-NLS-1$
    pnAttributes.setLayout(new GridLayout(3, 1));
    pnAttributes.add(pnReadable, null);
    pnAttributes.add(pnWritable, null);
    pnAttributes.add(pnHidden, null);

    pnReadable.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
    pnReadable.add(cbReadable, null);
    pnReadable.add(lbReadable, null);
    lbReadable.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".attributes.readable"))); //$NON-NLS-1$
    cbReadable.setEnabled(false);
    
    pnWritable.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
    pnWritable.add(cbWritable, null);
    pnWritable.add(lbWritable, null);
    lbWritable.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".attributes.writable"))); //$NON-NLS-1$
    cbWritable.setEnabled(false);
    
    pnHidden.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
    pnHidden.add(cbHidden, null);
    pnHidden.add(lbHidden, null);
    lbHidden.setText(ActionBundle.getString(ACTION_NAME_FILE_PROPERTIES.concat(".attributes.hidden"))); //$NON-NLS-1$
    cbHidden.setEnabled(false);

    pnClose.setLayout(new FlowLayout(FlowLayout.TRAILING));
    pnClose.add(btClose, null);

    GUIUtilities.setLocalizedText(btClose, JNPadBundle.getCloseButtonText());

    btClose.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent e) {
        dispose();
      }
    });

    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  }

  /**
   * Escape pressed.
   *
   * @see jnpad.ui.EscapableDialog#escapePressed()
   */
  @Override
  protected void escapePressed() {
    dispose();
  }

  /**
   * Init.
   */
  private void init() {
    lbFileName.setText(file.getName());
    lbPathValue.setText(file.getAbsolutePath());
    
    try {
      BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
      String encoding = GUIUtilities.detectEncoding(in);
      if (encoding == null || !Charset.isSupported(encoding)) {
        encoding = Config.FILE_ENCODING.getValue();
      }
      else {
        lbEncodingValue.setText(encoding);
      }

      byte[] buffer = new byte[in.available()];
      
      // leer todos los bytes disponibles en el buffer
      in.read(buffer);
      in.close();

      // encoding
      String s;
      try {
        s = new String(buffer, 0, buffer.length, encoding);
      }
      catch (Exception ex) { // no deberķa pasar
        s = new String(buffer, 0, buffer.length, Config.FILE_ENCODING.getDefault());
      }

      GUIUtilities.StringConversion conversion = GUIUtilities.detectEOL(s);
      lbEOLValue.setText(conversion.getLineSeparator().getLongName());
      lbLinesValue.setText(String.valueOf(conversion.getLineCount()));
    }
    catch (Exception ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
    }
    
    int count = 0;
    double tempSize = file.length();
    double prevSize = tempSize;

    // Keep dividing by 1024 until you get the largest unit that goes
    // into this file's size.
    while (count < 4 && ((tempSize = prevSize / 1024f) >= 1)) {
      prevSize = tempSize;
      count++;
    }

    String suffix = null;
    switch (count) {
      case 0 : suffix = "bytes"; break; //$NON-NLS-1$
      case 1 : suffix = "KB"   ; break; //$NON-NLS-1$
      case 2 : suffix = "MB"   ; break; //$NON-NLS-1$
      case 3 : suffix = "GB"   ; break; //$NON-NLS-1$
      case 4 : suffix = "TB"   ; break; //$NON-NLS-1$
      default:
          break; //Keep FindBugs happy
     }

    NumberFormat fileSizeFormat = NumberFormat.getNumberInstance();
    fileSizeFormat.setGroupingUsed(true);
    fileSizeFormat.setMinimumFractionDigits(0);
    fileSizeFormat.setMaximumFractionDigits(1);
    lbSizeValue.setText(fileSizeFormat.format(prevSize) + " " + suffix); //$NON-NLS-1$
    
    SimpleDateFormat dateFormat;
    try {
      dateFormat = new SimpleDateFormat(Config.DATE_FORMAT.getValue());
    }
    catch (Exception ex) {
      LOGGER.log(Level.WARNING, ex.getMessage(), ex);
      dateFormat = new SimpleDateFormat();
    }
    lbModifiedValue.setText(dateFormat.format(new Date(file.lastModified())));
    
    cbHidden.setSelected(file.isHidden());
    cbWritable.setSelected(file.canWrite());
    cbReadable.setSelected(file.canRead());
  }

}
////////////////////////////////////////////////////////////////////////////////
