/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.globalization;

import com.arsdigita.initializer.Configuration;
import com.arsdigita.initializer.InitializationException;
import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.SessionManager;
import com.arsdigita.persistence.TransactionContext;

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 * Initialize the Globalization package
 *
 * @version $Revision: #14 $ $Date: 2004/04/07 $
 */
public class Initializer implements com.arsdigita.initializer.Initializer {

    private static final String DEFAULT_CHARSET = "defaultCharset";
    private static final String CHARSETS = "charsets";
    private static final String LOCALES  = "locales";

    private static final Logger s_log = Logger.getLogger(Initializer.class);

    private Configuration m_conf = new Configuration();

    public Initializer() throws InitializationException {
        m_conf.initParameter
            (CHARSETS,
             "Recognized character sets",
             List.class);

        m_conf.initParameter
            (LOCALES,
             "Recognized locales",
             List.class);
        
        m_conf.initParameter
            (DEFAULT_CHARSET,
             "Default character set for locales not listed",
             String.class);
    }

    public Configuration getConfiguration() {
        return m_conf;
    }

    public void startup() throws InitializationException {
        TransactionContext txn = SessionManager.getSession().
            getTransactionContext();
        txn.beginTxn();

        if ( ! isLoaded() ) {
            s_log.info("Globalization Initializer is loading.");
            load();
        }
        LocaleNegotiator.setApplicationLocaleProvider
            (new ApplicationLocaleProvider());
        LocaleNegotiator.setClientLocaleProvider(new ClientLocaleProvider());
        LocaleNegotiator.setSystemLocaleProvider(new SystemLocaleProvider());

        String defaultCharset = (String)m_conf.getParameter(DEFAULT_CHARSET);
        
        Globalization.setDefaultCharset(defaultCharset);

        txn.commitTxn();        
    }

    public void shutdown() {}

    private static boolean isLoaded() {
        DataCollection charsets = SessionManager.getSession().
            retrieve(Charset.BASE_DATA_OBJECT_TYPE);
        boolean result = (charsets.size() > 0);
        charsets.close();
        return result;
    }

    private void load() throws InitializationException {
        List charsets = (List) m_conf.getParameter(CHARSETS);
        if ( charsets == null ) {
            throw new InitializationException
                ("You must specify at least one charset in the \"" + CHARSETS +
                 "\" parameter of the globalization initaliazer in the init " +
                 " file. ISO-8859-1 would be a good first choice.");
        }

        Map charsetMap = new HashMap();

        for (Iterator i=charsets.iterator(); i.hasNext(); ) {
            String charsetName = (String) i.next();

            // Check if this is a valid charset.  Is there a better way to do
            // this? - vadimn@redhat.com, Mon 2002-07-29 14:47:41 -0400
            try {
                new OutputStreamWriter(new ByteArrayOutputStream(), charsetName);
            } catch (UnsupportedEncodingException ex) {
                throw new InitializationException
                    (charsetName + " is not a supported charset", ex);
            }
            Charset charset = new Charset();
            charset.setCharset(charsetName);
            charset.save();
            charsetMap.put(charsetName, charset);
        }

        List locales = (List) m_conf.getParameter(LOCALES);

        if ( locales == null ) {
            throw new InitializationException
                ("You must specify at least one locale in the \"" + LOCALES +
                 "\" parameter of the globalization initializer section of " +
                 "the init file. The \"en\" locale is probably required.");
        }

        for (Iterator i=locales.iterator(); i.hasNext(); ) {
            List localeData = (List) i.next();
            String language    = (String) localeData.get(0);
            String country     = (String) localeData.get(1);
            String variant     = (String) localeData.get(2);
            String charsetName = (String) localeData.get(3);
            Locale locale = new Locale(language, country, variant);

            Charset defaultCharset = (Charset) charsetMap.get(charsetName);
            if ( defaultCharset == null ) {
                throw new InitializationException
                    ("You must list " + charsetName + " in the \"" + CHARSETS +
                     "\" parameter before using it in the \"" + LOCALES +
                     "\" parameter.");
            }
            locale.setDefaultCharset(defaultCharset);
            locale.save();
        }
    }
}
