package net.sourceforge.phpdt.tidy;

import java.io.File;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import net.sourceforge.phpdt.tidy.preferences.IPreferenceConstants;
import net.sourceforge.phpdt.tidy.w3c.Configuration;
import net.sourceforge.phpdt.tidy.w3c.Tidy;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

/**
 * The main plugin class to be used in the desktop.
 */
public class JtidyPlugin extends AbstractUIPlugin implements IPreferenceConstants {
  //The shared instance.
  private static JtidyPlugin fPlugin;
  //Resource bundle.
  private ResourceBundle fResourceBundle;

  private Tidy fTidy;
  private boolean fUseConfigurationFile;
  public static String MARKER_NAME = "net.sourceforge.phpdt.tidy.MarkerName";

  /**
   * The constructor.
   */
  public JtidyPlugin(IPluginDescriptor descriptor) {
    super(descriptor);
    fPlugin = this;
    try {
      fResourceBundle = ResourceBundle.getBundle("net.sourceforge.phpdt.tidy.JtidyPluginResources");
    } catch (MissingResourceException x) {
      fResourceBundle = null;
    }
    initTidy();
  }

  /* (non-Javadoc)
   * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeDefaultPreferences(org.eclipse.jface.preference.IPreferenceStore)
   */
  protected void initializeDefaultPreferences(IPreferenceStore store) {
    store.setDefault(GENERAL_CONFIG_FILE, ""); //$NON-NLS-1$
    store.setDefault(GENERAL_USE_CONFIG_FILE, "false"); //$NON-NLS-1$

    store.setDefault(GENERAL_TIDY_MARK, "true"); //$NON-NLS-1$
    store.setDefault(GENERAL_SHOW_WARNINGS, "true"); //$NON-NLS-1$
    store.setDefault(GENERAL_QUIET, "false"); //$NON-NLS-1$
    store.setDefault(GENERAL_EMACS, "false"); //$NON-NLS-1$
    store.setDefault(GENERAL_KEEP_FILE_TIMES, "true"); //$NON-NLS-1$    

    store.setDefault(WRAP_ATT_VALS, "false"); //$NON-NLS-1$
    store.setDefault(WRAP_SCRIPTLETS, "false"); //$NON-NLS-1$
    store.setDefault(WRAP_SECTION, "true"); //$NON-NLS-1$
    store.setDefault(WRAP_ASP, "true"); //$NON-NLS-1$
    store.setDefault(WRAP_JSTE, "true"); //$NON-NLS-1$
    store.setDefault(WRAP_PHP, "true"); //$NON-NLS-1$
    store.setDefault(INDENT_ATTRIBUTES, "false"); //$NON-NLS-1$
    store.setDefault(LITERAL_ATTRIBS, "false"); //$NON-NLS-1$

    //    store.setDefault(TYPE_TREAD_AS_XML, "false"); //$NON-NLS-1$
    //    store.setDefault(TYPE_DOCTYPE, "false"); //$NON-NLS-1$

    store.setDefault(OUTPUT_MAKE_CLEAR, "false"); //$NON-NLS-1$
    store.setDefault(OUTPUT_STRIP_WORD, "false"); //$NON-NLS-1$
    store.setDefault(OUTPUT_ENCLOSE_BODY_TEXT, "false"); //$NON-NLS-1$
    store.setDefault(OUTPUT_ENCLOSE_BLOCK_TEXT, "false"); //$NON-NLS-1$

    store.setDefault(OUT_AS_RAW, "false"); //$NON-NLS-1$
    store.setDefault(OUT_UPPER_TAGS, "false"); //$NON-NLS-1$
    store.setDefault(OUT_UPPER_ATTR, "false"); //$NON-NLS-1$
    store.setDefault(OUT_BREAK_BR, "false"); //$NON-NLS-1$
    store.setDefault(OUT_WRAP_ATTR_VALUES, "false"); //$NON-NLS-1$
    store.setDefault(OUT_WRAP_SCRIPS, "false"); //$NON-NLS-1$

    store.setDefault(GENERAL_TIDY_MARK, "true"); //$NON-NLS-1$
  }

  /**
   * Initialises the Tidy Instance and registers the Preference Listener.
   */
  private void initTidy() {
    fTidy = new Tidy();
    String rawConfigFileName = getPreferenceStore().getString(GENERAL_CONFIG_FILE);
    updateTidyConfig(rawConfigFileName);
    IPropertyChangeListener listener = new IPropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent event) {
        String propName = event.getProperty();
        IPreferenceStore store = JtidyPlugin.getDefault().getPreferenceStore();
        Configuration configuration = fTidy.getConfiguration();
        Object value = event.getNewValue();

        if (value instanceof Boolean) {
          boolean enabled = ((Boolean) value).booleanValue();
          if (propName.equals(GENERAL_USE_CONFIG_FILE)) {
            fUseConfigurationFile = enabled;
            initConfiguration();
            return;
          }
          fUseConfigurationFile = store.getBoolean(GENERAL_USE_CONFIG_FILE);
          if (!fUseConfigurationFile) {
            if (propName.equals(GENERAL_TIDY_MARK)) {
              configuration.TidyMark = enabled;
            }
            if (propName.equals(GENERAL_SHOW_WARNINGS)) {
              configuration.ShowWarnings = enabled;
            }
            if (propName.equals(GENERAL_QUIET)) {
              configuration.Quiet = enabled;
            }
            if (propName.equals(GENERAL_EMACS)) {
              configuration.Emacs = enabled;
            }
            if (propName.equals(GENERAL_KEEP_FILE_TIMES)) {
              configuration.KeepFileTimes = enabled;
            }
            // wrap / indent
            if (propName.equals(WRAP_ATT_VALS)) {
              configuration.WrapAttVals = enabled;
            }
            if (propName.equals(WRAP_SCRIPTLETS)) {
              configuration.WrapScriptlets = enabled;
            }
            if (propName.equals(WRAP_SECTION)) {
              configuration.WrapSection = enabled;
            }
            if (propName.equals(WRAP_ASP)) {
              configuration.WrapAsp = enabled;
            }
            if (propName.equals(WRAP_JSTE)) {
              configuration.WrapJste = enabled;
            }
            if (propName.equals(WRAP_PHP)) {
              configuration.WrapPhp = enabled;
            }
            if (propName.equals(INDENT_ATTRIBUTES)) {
              configuration.IndentAttributes = enabled;
            }
            if (propName.equals(LITERAL_ATTRIBS)) {
              configuration.LiteralAttribs = enabled;
            }

            //            if (propName.equals(TYPE_TREAD_AS_XML)) {
            //              configuration.XmlTags = enabled;
            //            }
            //            if (propName.equals(TYPE_DOCTYPE)) {
            //              configuration.XmlPi = enabled;
            //            }                

            if (propName.equals(OUTPUT_MAKE_CLEAR)) {
              configuration.MakeClean = enabled;
            }

            if (propName.equals(OUTPUT_ENCLOSE_BODY_TEXT)) {
              configuration.EncloseBodyText = enabled;
            }
            if (propName.equals(OUTPUT_ENCLOSE_BLOCK_TEXT)) {
              configuration.EncloseBlockText = enabled;
            }
            if (propName.equals(OUTPUT_STRIP_WORD)) {
              configuration.Word2000 = enabled;
            }
            //            if (propName.equals(OUTPUT_DEFAULT_ALT_TEXT)) {
            //              configuration. = enabled;
            //            } 

            if (propName.equals(OUT_AS_RAW)) {
              configuration.RawOut = enabled;
            }
            if (propName.equals(OUT_UPPER_TAGS)) {
              configuration.UpperCaseTags = enabled;
            }
            if (propName.equals(OUT_UPPER_ATTR)) {
              configuration.UpperCaseAttrs = enabled;
            }

          }
        } else if (value instanceof String) {
          if (fUseConfigurationFile) {
            if (propName.equals(GENERAL_CONFIG_FILE)) {
              updateTidyConfig((String) value);
            }
          } else {
            if (propName.equals(OUTPUT_DEFAULT_ALT_TEXT)) {
              configuration.altText = (String) value;
            }
            if (propName.equals(INPUT_NEW_EMPTY_TAGS)) {
              configuration.parseEmptyTagNames((String) value, null);
            }
            if (propName.equals(INPUT_NEW_INLINE_TAGS)) {
              configuration.parseInlineTagNames((String) value, null);
            }
            if (propName.equals(INPUT_NEW_BLOCKLEVEL_TAGS)) {
              configuration.parseBlockTagNames((String) value, null);
            }
            if (propName.equals(INPUT_NEW_PRE_TAGS)) {
              configuration.parsePreTagNames((String) value, null);
            }
          }
        }
      }
    };

    getPreferenceStore().addPropertyChangeListener(listener);
    initConfiguration();
  }

  private void initConfiguration() {
    IPreferenceStore store = JtidyPlugin.getDefault().getPreferenceStore();

    fUseConfigurationFile = store.getBoolean(GENERAL_USE_CONFIG_FILE);
    Configuration configuration = fTidy.getConfiguration();

    String value;
    if (fUseConfigurationFile) {
      if ((value = store.getString(GENERAL_CONFIG_FILE)) != null) {
        updateTidyConfig((String) value);
      }
    } else {

      configuration.TidyMark = store.getBoolean(GENERAL_TIDY_MARK);
      configuration.ShowWarnings = store.getBoolean(GENERAL_SHOW_WARNINGS);
      configuration.Quiet = store.getBoolean(GENERAL_QUIET);
      configuration.Emacs = store.getBoolean(GENERAL_EMACS);
      configuration.KeepFileTimes = store.getBoolean(GENERAL_KEEP_FILE_TIMES);

      configuration.WrapAttVals = store.getBoolean(WRAP_ATT_VALS);
      configuration.WrapScriptlets = store.getBoolean(WRAP_SCRIPTLETS);
      configuration.WrapSection = store.getBoolean(WRAP_SECTION);
      configuration.WrapAsp = store.getBoolean(WRAP_ASP);
      configuration.WrapJste = store.getBoolean(WRAP_JSTE);
      configuration.WrapPhp = store.getBoolean(WRAP_PHP);
      configuration.IndentAttributes = store.getBoolean(INDENT_ATTRIBUTES);
      configuration.LiteralAttribs = store.getBoolean(LITERAL_ATTRIBS);

      configuration.MakeClean = store.getBoolean(OUTPUT_MAKE_CLEAR);
      configuration.EncloseBodyText = store.getBoolean(OUTPUT_ENCLOSE_BODY_TEXT);
      configuration.EncloseBlockText = store.getBoolean(OUTPUT_ENCLOSE_BLOCK_TEXT);
      configuration.Word2000 = store.getBoolean(OUTPUT_STRIP_WORD);
      if ((value = store.getString(OUTPUT_DEFAULT_ALT_TEXT)) != null) {
        configuration.altText = value;
      }
      
      configuration.RawOut = store.getBoolean(OUT_AS_RAW);
      configuration.UpperCaseTags = store.getBoolean(OUT_UPPER_TAGS);
      configuration.UpperCaseAttrs = store.getBoolean(OUT_UPPER_ATTR);
      
      if ((value = store.getString(INPUT_NEW_EMPTY_TAGS)) != null) {
        configuration.parseEmptyTagNames(value, null);
      }
      if ((value = store.getString(INPUT_NEW_INLINE_TAGS)) != null) {
        configuration.parseInlineTagNames(value, null);
      }
      if ((value = store.getString(INPUT_NEW_BLOCKLEVEL_TAGS)) != null) {
        configuration.parseBlockTagNames(value, null);
      }
      if ((value = store.getString(INPUT_NEW_PRE_TAGS)) != null) {
        configuration.parsePreTagNames(value, null);
      }
    }
  }

  /**
   * Updates the configuration of the tidy instance with content of the given
   * file, if ths file exists. Returns silently on error.
   * 
   * @param rawConfigFileName
   */
  private void updateTidyConfig(String rawConfigFileName) {
    File config = new File(rawConfigFileName);
    if (config.exists()) {
      fTidy.setConfigurationFromFile(config.getAbsolutePath());
    }
  }

  /**
   * Returns the shared instance.
   */
  public static JtidyPlugin getDefault() {
    return fPlugin;
  }

  /**
   * Returns the workspace instance.
   */
  public static IWorkspace getWorkspace() {
    return ResourcesPlugin.getWorkspace();
  }

  /**
   * Returns the string from the plugin's resource bundle,
   * or 'key' if not found.
   */
  public static String getResourceString(String key) {
    ResourceBundle bundle = JtidyPlugin.getDefault().getResourceBundle();
    if (bundle == null) {
      return key;
    }
    try {
      return bundle.getString(key);
    } catch (MissingResourceException e) {
      return key;
    }

  }

  /**
   * Returns the plugin's resource bundle,
   */
  public ResourceBundle getResourceBundle() {
    return fResourceBundle;
  }

  /**
   * Returns the Tidy instance for this resource. Curently the resource can be
   * null, I just copied a similar conzept from a differnt Project, which uses
   * a per Project configuration.
   * @param resource
   * @return Tidy
   */

  public static Tidy getTidyInstance(IResource resource) {
    //IProject project = resource.getProject();
    //TODO: bind the instance to the resource...
    if (getDefault().fTidy == null) {
      getDefault().initTidy();
    }
    return getDefault().fTidy;
  }
  /**
	 * This method is called upon plug-in activation
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
	}

	/**
	 * This method is called when the plug-in is stopped
	 */
	public void stop(BundleContext context) throws Exception {
		super.stop(context);
	}
}