package converttoutf;
/**
 * License: GPLv3+.
 * Author: Rinat Bikov <becase@altlinux.org>
 */

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Locale;

/**
 * Encoding converter for spec files from various encoding to utf-8 encoding
 * @author Rinat_Bikov
 *
 */
public class Converter {
    /**
     * Default input encoding
     */
    private final String defaultEncoding = "utf-8";
    /**
     * Output encoding
     */
    private final String outputEncoding = "utf-8";
    /**
     * First search encoding string
     */
    private final char[] searchOne = "Summary(".toCharArray();
    /**
     * Second search encoding string
     */
    private final char[] searchTwo = "%description -l ".toCharArray();
    /**
     * Position in first
     */
    private int[] posOne = {0};
    /**
     * Position in second
     */
    private int[] posTwo = {0};
    /**
     * Simple Knuth Morris Pratt algorithm with zero suffix array
     * @param ch current character
     * @param ar char array for search
     * @param pos current position
     * @return true, if founded sequence of ar characters
     */
    private boolean isMatch(char ch, char [] ar, int[] pos) {
        if (ch == ar[pos[0]]) {
            pos[0]++;
        } else {
            pos[0] = 0;
        }
        if (pos[0] == ar.length) {
            pos[0] = 0;
            return true;
        }
        return false;
    }
    /**
     * Is character in locale-encoding pair
     * @param ch current character
     * @return true, if ch in locale-encoding pair, false otherwise
     */
    private boolean encodingValue(char ch){
        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '.' || ch == '_' || ch == '-';
    }
    /**
     * Get pair of locale and encoding for current locale-encoding pair
     * @param str locale-encoding pair
     * @return array with locale and encoding
     */
    private String [] getLocaleAndEncoding(String str) {
        String [] res = new String[2];
        int indx = str.indexOf('.');
        int len = str.length();
        if (indx < 0) {
            indx = len;
        }
        res[0] = str.substring(0, indx);
        res[1] = null;
        if (indx < len) {
            res[1] = str.substring(indx + 1);
        }
        return res;
    }
    /**
     * Convert input stream characters to output utf-8
     */
    public void convert() {
        BufferedInputStream bis = null;
        OutputStreamWriter out = null;
        ByteArrayOutputStream byteOut = null;
        try {
            bis = new BufferedInputStream(System.in);
            out = new OutputStreamWriter(System.out, outputEncoding);
            byteOut = new ByteArrayOutputStream();
            int byt = 0;
            char ch = 0;
            boolean encodingStart = false;
            boolean inEncoding = false;
            StringBuilder sb = null;
            String currenEncoding = defaultEncoding;
            while ((byt = bis.read()) != -1) {
                ch = (char) byt;
                byteOut.write(byt);
                encodingStart = isMatch(ch, searchOne, posOne);
                encodingStart = isMatch(ch, searchTwo, posTwo) || encodingStart;
                if (inEncoding) {
                    if (!encodingValue(ch)) {
                        String[] res = getLocaleAndEncoding(sb.toString());
                        String enc = res[1] != null ? res[1] : defaultEncoding;
                        try {
                            Locale.setDefault(new Locale(res[0]));
                        }catch(Throwable th){
                        }
                        byte[] ar = byteOut.toByteArray();
                        byteOut = new ByteArrayOutputStream();
                        String p = new String(ar, currenEncoding);
                        currenEncoding = enc;
                        out.write(p);
                        out.flush();
                        inEncoding = false;
                    } else {
                        sb.append(ch);
                    }
                }
                if (encodingStart) {
                    inEncoding = true;
                    sb = new StringBuilder();
                }
            }
            out.write(new String(byteOut.toByteArray(), currenEncoding));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(bis);
            close(out);
            close(byteOut);
        }
    }
    /**
     * Close closeable object with exception treating
     * @param stream stream object to close
     */
    private void close(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String []args) {
        Converter conv = new Converter();
        conv.convert();
    }
}
