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.apache.http.protocol.HTTP;
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.net.URLDecoder;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LivePlayerStatusLoader extends HttpXmlLoader {
    private static final boolean DEBUG_LOGD = Release.IS_DEBUG & true;
    private static final boolean DEBUG_LOGV_PARSE = Release.IS_DEBUG & false;
    private static final boolean DEBUG_LOGD_PARSE = Release.IS_DEBUG & true;

    private static final String PATTERN_CONTENTS = "(rtmp://.+),(.+)";
    private static final String PATTERN_CONTENTS_CASE = "case:premium:(.+),default:(.+)";

    private String mLvNumber;
    private String mCookieUserSession;
    private Context mContext;

    private CallbackMessage<Void, String> mCallbackMessage;

    // XML解析データ
    private static class Rtmp {
        @SuppressWarnings("unused")
        public int is_fms;
        public String url;
        public String ticket;
    }
    private Rtmp mRtmp;
    private static class Contents {
        public String id;
        public int disableAudio;
        public int disableVideo;
        public int start_time;
        @SuppressWarnings("unused")
        public String text;

        public String parseUrl;
        public String parsePlaypath;
//        public String akamaiUser;
//        public String akamaiPassword;
        @SuppressWarnings("unused")
        public boolean isAkamai;
    }
    private static class Que {
        public int vpos;
        public String mail;
        public String name;
        @SuppressWarnings("unused")
        public String text;

        public String publishPlaypath;
        public String publishContent;
    }
    private static class Stream {
        public String watch_count;
        public String title;
        public String description;
        public String comment_count;
        @SuppressWarnings("unused")
        public String aspect;
        @SuppressWarnings("unused")
        public long base_time;
        @SuppressWarnings("unused")
        public long open_time;
        @SuppressWarnings("unused")
        public long end_time;
        public long start_time;
        public int archive;
        public ArrayList<Contents> contents_list;
        public ArrayList<Que> quesheet;
    }
    private Stream mStream;
    private static class TicketsStream {
        public String name;
        public String text;
    }
    private ArrayList<TicketsStream> mTickets;
    private static class User {
        public String room_label;
        public String room_seetno;
        public String user_id;
    }
    private User mUser;
    private static class Ms {
        public String addr;
        public String port;
        public String thread;
    }
    private Ms mMs;
    private long mTime;

    public LivePlayerStatusLoader(String lvNumber, String cookieUserSession,
            Context context) {
        mLvNumber = lvNumber;
        mCookieUserSession = cookieUserSession;
        mContext = context;
    }

    public void registerCallback(CallbackMessage<Void, String> callback) {
        mCallbackMessage = callback;
    }

    public String getRtmpUrl() {
        if (mRtmp == null) {
            return null;
        }
        return mRtmp.url;
    }
    public String getRtmpTicket() {
        if (mRtmp == null) {
            return null;
        }
        return mRtmp.ticket;
    }

    public String getContentsUrl() {
        if (mStream == null) {
            return null;
        }
        ArrayList<Contents> contentsList = mStream.contents_list;
        if (contentsList == null || contentsList.size() == 0) {
            return null;
        }
        // TODO 最初の１個で決め打ち
        return contentsList.get(0).parseUrl;
    }
    public String getContentsPlaypath() {
        if (mStream == null) {
            return null;
        }
        ArrayList<Contents> contentsList = mStream.contents_list;
        if (contentsList == null || contentsList.size() == 0) {
            return null;
        }
        // TODO 最初の１個で決め打ち
        String playpath = contentsList.get(0).parsePlaypath;
        if (mTickets == null) {
            return playpath;
        } else {
            for (TicketsStream stream : mTickets) {
                if (TextUtils.equals(stream.name, playpath)) {
                    return playpath + "?" + stream.text;
                }
            }
        }
        return null;
    }
//    public String getAkamaiUser() {
//        if (mContentsList == null || mContentsList.size() == 0) {
//            return null;
//        }
//        // TODO 最初の１個で決め打ち
//        return mContentsList.get(0).akamaiUser;
//    }
//    public String getAkamaiPassword() {
//        if (mContentsList == null || mContentsList.size() == 0) {
//            return null;
//        }
//        // TODO 最初の１個で決め打ち
//        return mContentsList.get(0).akamaiPassword;
//    }
//    public String getQuePlay() {
//        if (mQuesheet == null || mQuesheet.size() == 0) {
//            return null;
//        }
//        Matcher matcher = Pattern.compile("/play\\s+rtmp:(.+)\\s").matcher("");
//        for (Que que : mQuesheet) {
//            matcher.reset(que.text);
//            if (matcher.find()) {
//                return matcher.group(1);
//            }
//        }
//        return null;
//    }
    public String getQueContent() {
        if (mStream == null) {
            return null;
        }
        ArrayList<Que> quesheet = mStream.quesheet;
        if (quesheet == null || quesheet.size() == 0) {
            return null;
        }

        // TODO 最初の１個で決め打ち
        for (Que que : quesheet) {
            if (que.publishContent != null) {
//                if (que.publishContent.endsWith(".f4v")) {
                    return "mp4:" + que.publishContent;
//                } else {
//                    return que.publishContent;
//                }
            }
        }
        return null;
    }
    public String getQuePlaypath() {
        if (mStream == null) {
            return null;
        }
        ArrayList<Que> quesheet = mStream.quesheet;
        if (quesheet == null || quesheet.size() == 0) {
            return null;
        }

        // TODO 最初の１個で決め打ち
        for (Que que : quesheet) {
            if (que.publishPlaypath != null) {
                return que.publishPlaypath;
            }
        }
        return null;
    }
    public int getQueVpos() {
        if (mStream == null) {
            return 0;
        }
        ArrayList<Que> quesheet = mStream.quesheet;
        if (quesheet == null || quesheet.size() == 0) {
            return 0;
        }

        // TODO 最初の１個で決め打ち
        for (Que que : quesheet) {
            if (que.publishPlaypath != null) {
                return que.vpos;
            }
        }
        return 0;
    }

    public String getMsAddr() {
        if (mMs == null) {
            return null;
        }
        return mMs.addr;
    }
    public String getMsPort() {
        if (mMs == null) {
            return null;
        }
        return mMs.port;
    }
    public String getMsThread() {
        if (mMs == null) {
            return null;
        }
        return mMs.thread;
    }

    public String getRoomLabel() {
        if (mUser == null) {
            return null;
        }
        return mUser.room_label;
    }
    public String getRoomSeetNo() {
        if (mUser == null) {
            return null;
        }
        return mUser.room_seetno;
    }
    public String getUserId() {
        if (mUser == null) {
            return null;
        }
        return mUser.user_id;
    }

    public String getTitle() {
        if (mStream == null) {
            return null;
        }
        return mStream.title;
    }
    public String getDescription() {
        if (mStream == null) {
            return null;
        }
        return mStream.description;
    }
    public String getWatchCount() {
        if (mStream == null) {
            return null;
        }
        return mStream.watch_count;
    }
    public String getCommentCount() {
        if (mStream == null) {
            return null;
        }
        return mStream.comment_count;
    }
    public int getArchive() {
        if (mStream == null) {
            return 0;
        }
        return mStream.archive;
    }

    public long getTime() {
        return mTime;
    }
    public long getStartTime() {
        if (mStream == null) {
            return 0;
        }
        return mStream.start_time;
    }

    @Override
    protected HttpUriRequest createRequest() {
        HttpGet httpRequest = new HttpGet(
                "http://live.nicovideo.jp/api/getplayerstatus?v=" + mLvNumber);
        httpRequest.addHeader("Cookie", mCookieUserSession);
        return httpRequest;
    }

    @Override
    protected boolean createDataFromXml(String xmlBody) {
        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 ("getplayerstatus".equals(name)) {
                        try {
                            mTime = Long.parseLong(
                                    pullParser.getAttributeValue(null, "time"));
                        } catch (NumberFormatException e) {
                            if (DEBUG_LOGD_PARSE) {
                                Log.d(LOG_TAG, e.toString(), e);
                            }
                        }
                    } else if ("stream".equals(name)) {
                        parseStream(pullParser);
                    } else if ("rtmp".equals(name)) {
                        parseRtmp(pullParser);
                    } else if ("tickets".equals(name)) {
                        parseTickets(pullParser);
                    } else if ("user".equals(name)) {
                        parseUser(pullParser);
                    } else if ("ms".equals(name)) {
                        parseMs(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;
                }
            }

            if (DEBUG_LOGD) {
                StringBuilder buf = Log.buf().append("LivePlayerStatus:");
                if (mRtmp == null) {
                    buf.append(" rtmp=(null)");
                } else {
                    buf.append(" rtmp url=").append(mRtmp.url)
                        .append(" rtmp ticket=").append(mRtmp.ticket);
                }
                Log.d(LOG_TAG, buf.toString());
            }

            return true;
        } catch (XmlPullParserException e) {
            Log.e(LOG_TAG, e.toString(), e);
        } catch (IOException e) {
            Log.e(LOG_TAG, e.toString(), e);
        }
        return false;
    }

    @Override
    protected void dispatchOnFinished() {
        mCallbackMessage.sendMessageSuccess(null);
    }

    @Override
    protected void dispatchOnOccurredError(String errorMessage) {
        mCallbackMessage.sendMessageError(errorMessage);
    }

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

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

    private void parseContentsList(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        int next;
        String name = null;
        Contents contents = 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 ("contents".equals(name)) {
                    if (contents != null) {
                        throw new XmlPullParserException("<contents> duplicate nest");
                    }
                    contents = new Contents();
                    contents.id = pullParser.getAttributeValue(null, "id");
                    try {
                        contents.disableAudio = Integer.parseInt(
                                pullParser.getAttributeValue(null, "disableAudio"));
                    } catch (NumberFormatException e) {
                        if (DEBUG_LOGD_PARSE) {
                            Log.d(LOG_TAG, e.toString(), e);
                        }
                    }
                    try {
                        contents.disableVideo = Integer.parseInt(
                                pullParser.getAttributeValue(null, "disableVideo"));
                    } catch (NumberFormatException e) {
                        if (DEBUG_LOGD_PARSE) {
                            Log.d(LOG_TAG, e.toString(), e);
                        }
                    }
                    try {
                        contents.start_time = Integer.parseInt(
                                pullParser.getAttributeValue(null, "start_time"));
                    } catch (NumberFormatException e) {
                        if (DEBUG_LOGD_PARSE) {
                            Log.d(LOG_TAG, e.toString(), e);
                        }
                    }
                    if (DEBUG_LOGD_PARSE) {
                        Log.d(LOG_TAG, Log.buf().append("id=").append(contents.id)
                                .append(" disableAudio=").append(contents.disableAudio)
                                .append(" disableVideo=").append(contents.disableVideo)
                                .append(" start_time=").append(contents.start_time)
                                .toString());
                    }
                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.TEXT:
                assert name != null;
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logText(pullParser);
                }
                String text = pullParser.getText();
                assert mStream.contents_list != null;
                if ("contents".equals(name)) {
                    assert contents != null;
                    contents.text = text;

                    // TODO smile:smXXXX形式で動画を指定している物も
                    // TODO id=mainとid=subで２つcontentsがあるものが

                    String partText;
                    if (text.startsWith("case:")) {
                        SharedPreferences sharedPreferences = Util.getDefaultSharedPreferencesMultiProcess(mContext);
                        int authflag = sharedPreferences.getInt(NicoroConfig.AUTHFLAG, 0);
                        boolean isPremium = (authflag == 3);
                        Matcher matcher = Pattern.compile(PATTERN_CONTENTS_CASE
                                ).matcher(text);
                        if (matcher.find()) {
                            if (isPremium) {
                                partText = matcher.group(1);
                            } else {
                                partText = matcher.group(2);
                            }
                        } else {
                            partText = text;
                        }
                    } else {
                        partText = text;
                    }
                    partText = URLDecoder.decode(partText, HTTP.UTF_8);

                    contents.isAkamai = partText.startsWith("akamai:");
                    Matcher matcher = Pattern.compile(PATTERN_CONTENTS
                            ).matcher(partText);
                    if (matcher.find()) {
                        contents.parseUrl = matcher.group(1);
                        // TODO akamaiのuser名とpassword？
                        contents.parsePlaypath = matcher.group(2);
//                        if (isAkamai) {
//                            Matcher matcherAkamai = Pattern.compile("(.+)@(.+)"
//                                    ).matcher(contents.parseStream);
//                            if (matcherAkamai.find()) {
//                                contents.akamaiUser = matcherAkamai.group(1);
//                                contents.akamaiPassword = matcherAkamai.group(2);
//                            }
//                        }
                    }
                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                assert mStream.contents_list != null;
                if ("contents".equals(name)) {
                    assert contents != null;
                    mStream.contents_list.add(contents);
                    contents = null;
                } else if ("contents_list".equals(name)) {
                    return;
                } else {
                    // その他のタグはなさそうなので無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }

    private void parseQueSheet(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        int next;
        String name = null;
        Que que = 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 ("que".equals(name)) {
                    if (que != null) {
                        throw new XmlPullParserException("<que> duplicate nest");
                    }
                    que = new Que();
                    try {
                        que.vpos = Integer.parseInt(pullParser.getAttributeValue(null, "vpos"));
                    } catch (NumberFormatException e) {
                        if (DEBUG_LOGD_PARSE) {
                            Log.d(LOG_TAG, e.toString(), e);
                        }
                    }
                    que.mail = pullParser.getAttributeValue(null, "mail");
                    que.name = pullParser.getAttributeValue(null, "name");
                    if (DEBUG_LOGD_PARSE) {
                        Log.d(LOG_TAG, Log.buf().append("vpos=").append(que.vpos)
                                .append(" mail=").append(que.mail)
                                .append(" name=").append(que.name)
                                .toString());
                    }
                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.TEXT:
                assert name != null;
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logText(pullParser);
                }
                String text = pullParser.getText();
                assert mStream.quesheet != null;
                if ("que".equals(name)) {
                    assert que != null;
                    que.text = text;

                    Matcher matcher = Pattern.compile("/publish\\s+(.+)\\s+(.+)").matcher(text);
                    if (matcher.find()) {
                        que.publishPlaypath = matcher.group(1);
                        que.publishContent = matcher.group(2);
                    }

                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                assert mStream.quesheet != null;
                if ("que".equals(name)) {
                    assert que != null;
                    mStream.quesheet.add(que);
                    que = null;
                } else if ("quesheet".equals(name)) {
                    return;
                } else {
                    // その他のタグはなさそうなので無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }

    private void parseStream(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        if (mStream != null) {
            throw new XmlPullParserException("<stream> duplicate");
        }
        mStream = new Stream();

        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);
                }
                assert mStream != null;
                if ("contents_list".equals(name)) {
                    if (mStream.contents_list != null) {
                        throw new XmlPullParserException("<contents_list> duplicate");
                    }
                    mStream.contents_list = new ArrayList<Contents>();
                    parseContentsList(pullParser);
                } else if ("quesheet".equals(name)) {
                    if (mStream.quesheet != null) {
                        throw new XmlPullParserException("<quesheet> duplicate");
                    }
                    mStream.quesheet = new ArrayList<Que>();
                    parseQueSheet(pullParser);
                } else {
                    // その他のタグはとりあえず無視
                }
                break;
            case XmlPullParser.TEXT:
                assert name != null;
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logText(pullParser);
                }
                String text = pullParser.getText();
                try {
                    assert mStream != null;
                    if ("watch_count".equals(name)) {
                        mStream.watch_count = text;
                    } else if ("title".equals(name)) {
                        mStream.title = text;
                    } else if ("description".equals(name)) {
                        mStream.description = text;
                    } else if ("comment_count".equals(name)) {
                        mStream.comment_count = text;
                    } else if ("aspect".equals(name)) {
                        mStream.aspect = text;
                    } else if ("base_time".equals(name)) {
                        mStream.base_time = Long.parseLong(text);
                    } else if ("open_time".equals(name)) {
                        mStream.open_time = Long.parseLong(text);
                    } else if ("end_time".equals(name)) {
                        mStream.end_time = Long.parseLong(text);
                    } else if ("start_time".equals(name)) {
                        mStream.start_time = Long.parseLong(text);
                    } else if ("archive".equals(name)) {
                        mStream.archive = Integer.parseInt(text);
                    } else {
                        // その他のタグはとりあえず無視
                    }
                } catch (NumberFormatException e) {
                    Log.d(LOG_TAG, Log.buf().append("parseInt/Long failed:")
                            .append(text).toString());
                    // できる限り続行
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                assert mStream != null;
                if ("stream".equals(name)) {
                    return;
                } else {
                    // その他のタグはとりあえず無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }

    private void parseTickets(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        if (mTickets != null) {
            throw new XmlPullParserException("<tickets> duplicate");
        }
        mTickets = new ArrayList<TicketsStream>();

        int next;
        String name = null;
        TicketsStream ticketsStream = 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 ("stream".equals(name)) {
                    if (ticketsStream != null) {
                        throw new XmlPullParserException("<stream> duplicate nest");
                    }
                    ticketsStream = new TicketsStream();
                    ticketsStream.name = pullParser.getAttributeValue(null, "name");
                    if (DEBUG_LOGD_PARSE) {
                        Log.d(LOG_TAG, Log.buf().append("name=").append(ticketsStream.name)
                                .toString());
                    }
                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.TEXT:
                assert name != null;
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logText(pullParser);
                }
                String text = pullParser.getText();
                assert mTickets != null;
                if ("stream".equals(name)) {
                    assert ticketsStream != null;
                    ticketsStream.text = text;
                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                assert mTickets != null;
                if ("stream".equals(name)) {
                    assert ticketsStream != null;
                    mTickets.add(ticketsStream);
                    ticketsStream = null;
                } else if ("tickets".equals(name)) {
                    return;
                } else {
                    // その他のタグはなさそうなので無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }

    private void parseRtmp(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        if (mRtmp != null) {
            throw new XmlPullParserException("<rtmp> duplicate");
        }
        mRtmp = new Rtmp();
        String is_fms = pullParser.getAttributeValue(null, "is_fms");
        if (is_fms != null) {
            try {
                mRtmp.is_fms = Integer.parseInt(is_fms);
            } catch (NumberFormatException e) {
                if (DEBUG_LOGD_PARSE) {
                    Log.d(LOG_TAG, e.toString(), e);
                }
            }
        }

        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();
                assert mRtmp != null;
                if ("url".equals(name)) {
                    mRtmp.url = text;
                } else if ("ticket".equals(name)) {
                    mRtmp.ticket = text;
                } else {
                    // その他のタグはとりあえず無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                if ("rtmp".equals(name)) {
                    assert mRtmp != null;
                    return;
                } else {
                    // その他のタグはとりあえず無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }

    private void parseUser(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        if (mUser != null) {
            throw new XmlPullParserException("<user> duplicate");
        }
        mUser = new User();

        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();
                assert mUser != null;
                if ("room_label".equals(name)) {
                    mUser.room_label = text;
                } else if ("room_seetno".equals(name)) {
                    mUser.room_seetno = text;
                } else if ("user_id".equals(name)) {
                    mUser.user_id = text;
                } else {
                    // その他のタグはとりあえず無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                assert mUser != null;
                if ("user".equals(name)) {
                    return;
                } else {
                    // その他のタグはとりあえず無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }

    private void parseMs(XmlPullParser pullParser)
    throws XmlPullParserException, IOException {
        if (mMs != null) {
            throw new XmlPullParserException("<ms> duplicate");
        }
        mMs = new Ms();

        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();
                assert mMs != null;
                if ("addr".equals(name)) {
                    mMs.addr = text;
                } else if ("port".equals(name)) {
                    mMs.port = text;
                } else if ("thread".equals(name)) {
                    mMs.thread = text;
                } else {
                    // その他のタグはなさそうなので無視
                }
                break;
            case XmlPullParser.END_TAG:
                name = pullParser.getName();
                if (DEBUG_LOGD_PARSE) {
                    XmlLoader.logEndTag(pullParser, name);
                }
                assert mMs != null;
                if ("ms".equals(name)) {
                    return;
                } else {
                    // その他のタグはなさそうなので無視
                }
                name = null;
                break;
            default:
                break;
            }
        }
        throw new XmlPullParserException("END_DOCUMENT is found before END_TAG");
    }
}
