package jp.sourceforge.nicoro;

import static jp.sourceforge.nicoro.Log.LOG_TAG;

import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Xml;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Locale;

public class ConfigureNgClient extends HttpXmlLoader implements ConfigureNgClientInterface {
    private static final boolean DEBUG_LOGV_PARSE = Release.IS_DEBUG & false;
    private static final boolean DEBUG_LOGD_PARSE = Release.IS_DEBUG & true;

    private String mCookie;
    private Context mContext;
    private EventListener mEventListener;

    private ArrayList<NgClient> mNgClients;

    public ConfigureNgClient(String cookie, Context context) {
        mCookie = cookie;
        mContext = context;
    }

    @Override
    public boolean isNull() {
        return false;
    }

    @Override
    public ArrayList<NgClient> getNgClients() {
        return mNgClients;
    }

    @Override
    protected HttpUriRequest createRequest() {
        HttpGet httpRequest = new HttpGet(
                "http://flapi.nicovideo.jp/api/configurengclient");
        httpRequest.addHeader("Cookie", mCookie);
        SharedPreferences sharedPreference = Util.getDefaultSharedPreferencesMultiProcess(mContext);
        String userAgent = sharedPreference.getString(NicoroConfig.USER_AGENT, null);
        if (userAgent != null) {
            httpRequest.setHeader("User-Agent", userAgent);
        }
        return httpRequest;
    }

    @Override
    protected String getXmlParseErrorString() {
        return "configurengclient: XML parse failed";
    }

    @Override
    protected boolean createDataFromXml(String xmlBody) {
        parse(xmlBody);
        return true;
    }

    private void parse(String xmlBody) {
        mNgClients = new ArrayList<NgClient>();

        XmlPullParser pullParser = Xml.newPullParser();
        try {
            pullParser.setInput(new StringReader(xmlBody));

            int next;
            String name = null;
            while ((next = pullParser.next()) != XmlPullParser.END_DOCUMENT) {
                if (DEBUG_LOGV_PARSE) {
                    Log.v(LOG_TAG, Log.buf().append("next=").append(next).toString());
                }
                switch (next) {
                case XmlPullParser.START_TAG:
                    name = pullParser.getName();
                    if (DEBUG_LOGD_PARSE) {
                        XmlLoader.logStartTag(pullParser, name);
                    }
                    if ("ngclient".equals(name)) {
                        parseNgClient(pullParser);
                    } else {
                        // その他のタグはとりあえず無視
                    }
                    break;
                case XmlPullParser.TEXT:
                    assert name != null;
                    if (DEBUG_LOGD_PARSE) {
                        XmlLoader.logText(pullParser);
                    }
                    // とりあえず無視
                    break;
                case XmlPullParser.END_TAG:
                    name = pullParser.getName();
                    if (DEBUG_LOGD_PARSE) {
                        XmlLoader.logEndTag(pullParser, name);
                    }
                    name = null;
                    // とりあえず無視
                    break;
                default:
                    break;
                }
            }
        } catch (XmlPullParserException e) {
            Log.d(LOG_TAG, e.toString(), e);
        } catch (IOException e) {
            Log.d(LOG_TAG, e.toString(), e);
        }
    }

    private void parseNgClient(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        int type = NG_TYPE_INVALID;
        String source = null;
        int next;
        String name = null;
        while ((next = pullParser.next()) != XmlPullParser.END_DOCUMENT) {
            if (DEBUG_LOGV_PARSE) {
                Log.v(LOG_TAG, Log.buf().append("next=").append(next).toString());
            }
            switch (next) {
            case XmlPullParser.START_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logStartTag(pullParser, name);
                }
                // とりあえず無視
                break;
            case XmlPullParser.TEXT:
                assert name != null;
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logText(pullParser);
                }
                String text = pullParser.getText();
                if ("type".equals(name)) {
                    if ("id".equals(text)) {
                        type = NG_TYPE_ID;
                    } else if ("word".equals(text)) {
                        type = NG_TYPE_WORD;
                    } else if ("command".equals(text)) {
                        type = NG_TYPE_COMMAND;
                    }
                } else if ("source".equals(name)) {
                    if (!TextUtils.isEmpty(text)) {
                        source = text;
                    }
                } else {
                    // とりあえず無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                if ("ngclient".equals(name)) {
                    if (type != NG_TYPE_INVALID && source != null) {
                        if (type == NG_TYPE_WORD) {
                            // 大文字小文字無視のためあらかじめ変換
                            source = convertCaseForNgWord(source);
                        }
                        mNgClients.add(new NgClient(type, source));
                    }
                    return;
                } else {
                    // とりあえず無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
    }

    @Override
    protected void dispatchOnFinished() {
        if (mEventListener != null) {
            mEventListener.onFinished(this);
        }
    }

    @Override
    protected void dispatchOnOccurredError(String errorMessage) {
        if (mEventListener != null) {
            mEventListener.onOccurredError(this, errorMessage);
        }
    }

    @Override
    protected boolean readAndCreateData(InputStream inDownload) throws IOException {
        String xmlBody = readEntityAndDecode(inDownload);
        return createDataFromXml(xmlBody);
    }

    @Override
    public void setEventListener(EventListener eventListener) {
        mEventListener = eventListener;
    }

    public static String convertCaseForNgWord(String text) {
        return text.toLowerCase(Locale.getDefault());
    }
}
