//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package de.ugoe.cs.autoquest.usability;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;

/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: 18.07.2012$
 * @author 2012, last modified by $Author: pharms$
 */
public enum UsabilityDefectDescription {
    
    TEXT_FIELD_INPUT_RATIO,
    TEXT_FIELD_INPUT_REPETITIONS,
    TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO;

    /** */
    private static final String DEFAULT_MESSAGES_FILE = "defectDescriptions_en.xml";

    /** */
    private static DefectDescriptions sDefectDescriptions;

    /** */
    private DefectDescription defectDescription;

    /**
     * TODO: comment
     * 
     * @param name
     * @param ordinal
     */
    private UsabilityDefectDescription() {
        init();
    }

    /**
     * TODO: comment
     * 
     */
    @SuppressWarnings("unchecked")
    private void init() {
        synchronized (this.getClass()) {
            if (sDefectDescriptions == null) {
                InputStream inputStream =
                    ClassLoader.getSystemResourceAsStream(DEFAULT_MESSAGES_FILE);

                try {
                    String packageName = DefectDescriptions.class.getPackage().getName();
                    JAXBContext jaxbContext = JAXBContext.newInstance(packageName);
                    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

                    sDefectDescriptions =
                        ((JAXBElement<DefectDescriptions>) unmarshaller.unmarshal(inputStream))
                            .getValue();
                }
                catch (Exception e) {
                    throw new RuntimeException
                        ("error while initializing usability defect descriptions", e);
                }
                finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        }
                        catch (IOException e) {
                            // ignore
                        }
                    }
                }
            }
        }

        for (DefectDescription description : sDefectDescriptions.getDefectDescription()) {
            if (this.name().equals(description.getDefectId())) {
                defectDescription = description;
                break;
            }
        }

        if (defectDescription == null) {
            throw new RuntimeException
                ("error while initializing usability defect descriptions. No " +
                 "description text available for description " + this.name());
        }
    }

    /**
   * 
   */
    public String[] getDescriptionParameters() {
        List<String> parameters = new ArrayList<String>();

        for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {
            if (fragment instanceof ParameterFragment) {
                parameters.add(((ParameterFragment) fragment).getParameterName());
            }
        }

        return parameters.toArray(new String[parameters.size()]);
    }

    /**
   * 
   */
    public String toString(Map<String, String> parameters) throws IllegalArgumentException {
        StringBuffer result = new StringBuffer();

        for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {
            if (result.length() > 0) {
                result.append(" ");
            }

            if (fragment instanceof ParameterFragment) {
                String value = null;
                if (parameters != null) {
                    value = parameters.get(((ParameterFragment) fragment).getParameterName());
                }

                if (value != null) {
                    result.append(value);
                }
                else {
                    throw new IllegalArgumentException
                        ("required parameter \"" +
                         ((ParameterFragment) fragment).getParameterName() +
                         "\" for usability defect description " + this.name() + " not provided");
                }
            }
            else {
                result.append(getFragmentString(fragment));
            }
        }

        return result.toString();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        StringBuffer result = new StringBuffer();

        int paramCount = 1;
        for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {
            if (result.length() > 0) {
                result.append(" ");
            }

            if (fragment instanceof ParameterFragment) {
                result.append("<parameter");
                result.append(paramCount++);
                result.append(">");
            }
            else {
                result.append(getFragmentString(fragment));
            }
        }

        return result.toString();
    }

    /**
     * TODO: comment
     * 
     * @param fragment
     * @return
     */
    private String getFragmentString(Object fragment) {
        String fragmentStr = fragment.toString().trim();

        fragmentStr = fragmentStr.replaceAll("\n", " ");

        while (fragmentStr.indexOf("  ") > -1) {
            fragmentStr = fragmentStr.replaceAll("  ", " ");
        }

        return fragmentStr;
    }

}
