/*
 * Copyright (c) 2008, Andrea Chiumenti.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.IOException;
import java.text.DateFormatSymbols;
import java.text.DecimalFormatSymbols;
import java.util.Calendar;
import java.util.Locale;
import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;

/**
 *
 * @author Andrea Chiumenti
 */
public class GenerateLocales {

    private StringWriter sw;
    private String fileName;

    public GenerateLocales() {
        fileName = "locales.lisp";
    }

    public void generateFile(String fileName) throws IOException {
        sw = new StringWriter();
        //sw.append("(defvar *locales* (make-hash-table :test 'equal))\n");
        sw.append(";;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-\n").
                append(";;; $Header: src/locales.lisp $\n").
                append("\n").
                append(";;; Copyright (c) 2008, Andrea Chiumenti.  All rights reserved.\n").
                append("\n").
                append(";;; Redistribution and use in source and binary forms, with or without\n").
                append(";;; modification, are permitted provided that the following conditions\n").
                append(";;; are met:\n").
                append("\n").
                append(";;;   * Redistributions of source code must retain the above copyright\n").
                append(";;;     notice, this list of conditions and the following disclaimer.\n").
                append("\n").
                append(";;;   * Redistributions in binary form must reproduce the above\n").
                append(";;;     copyright notice, this list of conditions and the following\n").
                append(";;;     disclaimer in the documentation and/or other materials\n").
                append(";;;     provided with the distribution.\n").
                append("\n").
                append(";;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED\n").
                append(";;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n").
                append(";;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n").
                append(";;; ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n").
                append(";;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n").
                append(";;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n").
                append(";;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n").
                append(";;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n").
                append(";;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n").
                append(";;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n").
                append(";;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n").
                append(";;; --*-- AUTOMATICALLY GENERATED - DO NOT EDIT !!!!! --*--\n\n").
                append("(in-package :claw)\n\n");
        File f = new File(fileName);
        if (f.exists()) {
            f.delete();
        }
        FileWriter fw = null;
        try {
            fw = new FileWriter(f);

            Locale[] locales = Locale.getAvailableLocales();

            for (int i = 0; i < locales.length; i++) {

                DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(new Locale(locales[i].getLanguage(), locales[i].getCountry()));
                DateFormatSymbols datefs = DateFormatSymbols.getInstance(new Locale(locales[i].getLanguage(), locales[i].getCountry()));
                Calendar cal = Calendar.getInstance(new Locale(locales[i].getLanguage(), locales[i].getCountry()));

                String locale;
                if (locales[i].getCountry().equals("")) {
                    locale = locales[i].getLanguage();
                } else {
                    locale = locales[i].getLanguage() + "_" + locales[i].getCountry().toUpperCase();

                }
                sw.append("(setf (gethash \"" + locale +
                        "\" *locales*)" +
                        "\n      (list ");
                sw.append("\n        :NUMBER-FORMAT " +
                        "(list :GROUPING-SEPARATOR " + encodeLispChar(dfs.getGroupingSeparator()) +
                        " :DECIMAL-SEPARATOR " + encodeLispChar(dfs.getDecimalSeparator()) +
                        " \"" + dfs.getInternationalCurrencySymbol() + "\"" + ")");

                sw.append("\n        :DATE-FORMAT (list");
                printDateSymbols("ampm", datefs.getAmPmStrings());
                printDateSymbols("months", datefs.getMonths());
                printDateSymbols("short-months", datefs.getShortMonths());
                printDateSymbols("first-day-of-the-week", cal.getFirstDayOfWeek());
                printDateSymbols("weekdays", datefs.getWeekdays());
                printDateSymbols("short-weekdays", datefs.getShortWeekdays());
                printDateSymbols("eras", datefs.getEras());

                sw.append(")))\n\n");

            }
            fw.write(sw.toString());
        } finally {
            if (fw != null) {
                fw.close();
            }
        }
        System.out.println(fileName + " successfully generated.");
    }

    private String encodeLispChar(char ch) {
        switch (ch) {
            case ' ': return "#\\SPACE";
            case 0: return "nil";
            default: return "#\\" + ch;
        }
                
                
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {


        GenerateLocales app = new GenerateLocales();

        if (args.length > 0) {
            String arg0 = args[0];
            if (arg0.equals("--help")) {
                app.printUsage();
                return;
            }
        }

        app.generateFile(app.fileName);
    }

    private void printUsage() {
        System.out.println("Usage:");
        System.out.println("  java " + GenerateLocales.class.getSimpleName() +
                " --help (prints usage)");
        System.out.println("  java " + GenerateLocales.class.getSimpleName() +
                " (generates output file)");
    }

    private void printDateSymbols(String symbol, String[] vals) {
        sw.append("\n                       :" +
                symbol.toUpperCase() +
                " '(");
        int i = 0;
        for (int x = 0; x < vals.length; x++) {
            if (!vals[x].equals("")) {
                if (i > 0) {
                    sw.append(" ");
                }
                sw.append("\"" +
                        vals[x] +
                        "\"");
                i++;
            }
        }
        sw.append(")");
    }
    
    private void printDateSymbols(String symbol, Number val) {
        sw.append("\n                       :" +
                symbol.toUpperCase() +
                " " + val);
        
    }

    public String getFileName() {
        return fileName;
    }
}
