package de.ids_mannheim.korap.plkexport;

import java.lang.StringBuffer;
import java.nio.charset.*;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import static java.nio.charset.CodingErrorAction.REPORT;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;

import java.io.IOException;
import java.io.Writer;

/**
 * This is a streaming exporter class for Rtf, so it's based on
 * a string buffer.
 */

public class RtfExporter extends MatchAggregator implements Exporter {

    private boolean firstMatch;

    private ObjectMapper mapper = new ObjectMapper();


    // final static Charset charset = Charset.forName("Windows-1252");
    final static CharsetEncoder charsetEncoder =
        Charset
        .forName("Windows-1252")
        .newEncoder()
        .onMalformedInput(REPORT)
        .onUnmappableCharacter(REPORT);

    StringBuilder sb;

        {
            firstMatch = true;
            sb = new StringBuilder(256);
        }

    @Override
    public String getMimeType () {
        return "application/rtf";
    };


    @Override
    public String getSuffix () {
        return "rtf";
    };
    
    
    @Override
    public void writeHeader (Writer w) throws IOException {
        w.append("{")
            .append("\\rtf1\\ansi\\deff0\n")
            .append("{\\colortbl;\\red0\\green0\\blue0;\\red127\\green127\\blue127;}\n")
            .append("{\\fonttbl{\\f0\\fcharset0 Times New Roman;}{\\f1\\fcharset1 Courier;}}\n");

        w.append("{\\footer\\pard\\ql\\fs18\\f0 ");
        rtfText(w, "@ Institut für Deutsche Sprache, Mannheim");

        // Page number
        w.append("  \\endash  \\chpgn / {\\field{\\*\\fldinst{\\fs18\\f0 NUMPAGES}}}");
        w.append("\\par}\n");

        // Title
        if (this.getQueryString() != null) {
            w.append("{\\pard\\fs28\\b\\f1\\ldblquote ");
            rtfText(w, this.getQueryString());
            w.append("\\rdblquote\\par}");
        };

        addVersion(w);
    };
    

    @Override
    public void writeFooter (Writer w) throws IOException {
        w.append("}");
    };
    

    @Override
    public void addMatch (JsonNode n, Writer w) throws IOException {

        try {

            MatchExport match = mapper.treeToValue(n, MatchExport.class);

            Snippet s = match.getSnippetO();

            w.append("\\line ");

            // Snippet
            w.append("{\\pard\\fs22\\f0\\qj ");
            if (s.hasMoreLeft()) {
                w.append("[...] ");
            };
            rtfText(w, s.getLeft());
            w.append(" {\\b ");
            rtfText(w, s.getMark());
            w.append("} ");
            rtfText(w, s.getRight());
            if (s.hasMoreRight()) {
                w.append(" [...]");
            };
            w.append("\\par}");

            // Reference
            w.append("{\\pard");
            w.append("\\qr\\fs20\\cf2\\f0 ");
            w.append("{\\b ");
            rtfText(w, match.getTitle());
            w.append(" von ");
            rtfText(w, match.getAuthor());
            w.append(" (");
            rtfText(w, match.getPubDate());
            w.append(")}");
            w.append("\\par}");

            // TextSigle
            w.append("{\\pard\\qr\\b\\fs20\\cf2\\f1 [");
            rtfText(w, match.getTextSigle());
            w.append("]\\par}");

            w.append("\n");

        } catch (JsonProcessingException jpe) {
            System.err.println(jpe);
            w.append("{\\pard {\\b Unable to process match} \\par}");
        };
    };


    /*
     * Get version for RTF document 
     */
    private void addVersion (Writer w) throws IOException {
        Version version = new Version(
            ExWSConf.VERSION_MAJOR,
            ExWSConf.VERSION_MINOR,
            ExWSConf.VERSION_PATCHLEVEL,
            null,
            null,
            null
            );

        w.append("{\\pard\\fs18\\f1 IDSExportPlugin-Version: ")
            .append(version.toString())
            .append("\\par}\n");
        return;
    };

    // Based on jrtf by Christian Ullenboom
    private static void rtfText(Writer w, String rawText) throws IOException {
        char c;
        for (int i = 0; i < rawText.length(); i++) {
            c = rawText.charAt( i ); 

            if (c == '\n')
                w.append("\\par\n");
            else if (c == '\t' )
                w.append("\\tab\n");
            else if (c == '\\' )
                w.append("\\\\");
            else if (c == '{' )
                w.append("\\{");
            else if (c == '}' )
                w.append("\\}");
            else if (c < 127) {
                w.append(c);
            }

            // Use Unicode and ask the char from the String object
            else {
                w.append("\\u" ).append(Integer.toString(c));

                if (!charsetEncoder.canEncode(c)) {
                    w.append("?");
                };

                try {
                    final ByteBuffer bytes = charsetEncoder.encode(
                        CharBuffer.wrap(String.valueOf(c))
                        );

                    // Treat byte as unsigned
                    final int unsignedCharByte = bytes.get() & 255;
                    w.append(String.format("\\'%02x", unsignedCharByte));
                }
                catch (CharacterCodingException err) {
                };
            };
        }
    };
};
