/* OdLib_Io - Copyright (c) 2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.opendocument.io.odtable;

import java.io.IOException;
import net.mapeadores.util.xml.XMLPart;
import net.mapeadores.util.xml.XMLWriter;


/**
 *
 * @author Vincent Calame
 */
public class DateStyleXMLPart extends XMLPart {

    public DateStyleXMLPart(XMLWriter xmlWriter) {
        super(xmlWriter);
    }

    public void writeFromJavaPattern(String dataStyleName, String pattern) throws IOException {
        this.startOpenTag("number:date-style")
                .addAttribute("style:name", dataStyleName)
                .endOpenTag();
        Parser parser = new Parser();
        parser.parsePattern(pattern);
        this.closeTag("number:date-style");
    }


    private class Parser {

        private StringBuilder litteralBuffer = new StringBuilder();

        private void parsePattern(String pattern) throws IOException {
            for (int pos = 0; pos < pattern.length(); pos++) {
                char cur = pattern.charAt(pos);
                if ((cur >= 'A' && cur <= 'Z') || (cur >= 'a' && cur <= 'z')) {
                    int start = pos++;
                    for (; pos < pattern.length() && pattern.charAt(pos) == cur; pos++);  // short loop
                    int count = pos - start;
                    // padding
                    if (cur == 'p') {
                        int pad = 0;
                        if (pos < pattern.length()) {
                            cur = pattern.charAt(pos);
                            if ((cur >= 'A' && cur <= 'Z') || (cur >= 'a' && cur <= 'z')) {
                                pad = count;
                                start = pos++;
                                for (; pos < pattern.length() && pattern.charAt(pos) == cur; pos++);  // short loop
                                count = pos - start;
                            }
                        }
                        if (pad == 0) {
                            throw new IllegalArgumentException(
                                    "Pad letter 'p' must be followed by valid pad pattern: " + pattern);
                        }
                        padNext(pad); // pad and continue parsing
                    }
                    switch (cur) {
                        case 'y':
                            writeYear(count);
                            break;
                        case 'M':
                        case 'L':
                            writeMonth(count);
                            break;
                        case 'd':
                            writeDayOfMonth(count);
                            break;
                        case 'E':
                        case 'e':
                        case 'c':
                            writeDayOfWeek(count);
                            break;
                        default:
                            appendLiteral(cur);
                    }
                    pos--;

                } else if (cur == '\'') {
                    // parse literals
                    int start = pos++;
                    for (; pos < pattern.length(); pos++) {
                        if (pattern.charAt(pos) == '\'') {
                            if (pos + 1 < pattern.length() && pattern.charAt(pos + 1) == '\'') {
                                pos++;
                            } else {
                                break;  // end of literal
                            }
                        }
                    }
                    if (pos >= pattern.length()) {
                        throw new IllegalArgumentException("Pattern ends with an incomplete string literal: " + pattern);
                    }
                    String str = pattern.substring(start + 1, pos);
                    if (str.length() == 0) {
                        appendLiteral('\'');
                    } else {
                        appendLiteral(str.replace("''", "'"));
                    }
                } else {
                    appendLiteral(cur);
                }
            }
            flush();
        }

        private void appendLiteral(char c) {
            litteralBuffer.append(c);
        }

        private void appendLiteral(String s) {
            litteralBuffer.append(s);
        }

        private void padNext(int pad) {
            for (int i = 0; i < pad; i++) {
                litteralBuffer.append(' ');
            }
        }

        private void writeYear(int count) throws IOException {
            flush();
            startOpenTag("number:year");
            if (count != 2) {
                addAttribute("number:style", "long");
            }
            closeEmptyTag();
        }

        private void writeMonth(int count) throws IOException {
            flush();
            startOpenTag("number:month");
            if ((count == 2) || (count == 4)) {
                addAttribute("number:style", "long");
            }
            if (count > 2) {
                addAttribute("number:textual", "true");
            }
            closeEmptyTag();
        }

        private void writeDayOfMonth(int count) throws IOException {
            flush();
            startOpenTag("number:day");
            if (count > 1) {
                addAttribute("number:style", "long");
            }
            closeEmptyTag();
        }

        private void writeDayOfWeek(int count) throws IOException {
            flush();
            startOpenTag("number:day-of-week");
            if (count == 4) {
                addAttribute("number:style", "long");
            }
            closeEmptyTag();
        }


        private void flush() throws IOException {
            if (litteralBuffer.length() > 0) {
                addSimpleElement("number:text", litteralBuffer.toString());
                litteralBuffer = new StringBuilder();
            }
        }

    }

}
