package jp.sourceforge.nicoro;

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

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

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.os.Message;
//import android.os.Parcel;
//import android.os.Parcelable;
import android.util.Xml;

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

	private String mVideoNumber;
	private int mPage;

	private int mTotalCount = 0;
	private int mPageCount = 0;
	private int mDataCount = 0;

    // FIXME ViewPagerのFragment復帰でどうしてもクラッシュすることがあるので、いったん実装を変える
	public static class Video implements /*Parcelable*/ Serializable {
		/**
         *
         */
        private static final long serialVersionUID = -1036330528517545167L;

        public String url;
		public String thumbnail;
		public String title;
		public int view;
		public int comment;
		public int mylist;
		public int length;
		public long time;

		public Video() {
		}


//        @Override
//        public int describeContents() {
//            return 0;
//        }
//
//        @Override
//        public void writeToParcel(Parcel dest, int flags) {
//            dest.writeString(url);
//            dest.writeString(thumbnail);
//            dest.writeString(title);
//            dest.writeInt(view);
//            dest.writeInt(comment);
//            dest.writeInt(mylist);
//            dest.writeInt(length);
//            dest.writeLong(time);
//        }
//
//        public static final Parcelable.Creator<RelatedVideoLoader.Video> CREATOR =
//                new Creator<RelatedVideoLoader.Video>() {
//            @Override
//            public Video[] newArray(int size) {
//                return new Video[size];
//            }
//
//            @Override
//            public Video createFromParcel(Parcel source) {
//                return new Video(source);
//            }
//        };
//
//        Video(Parcel source) {
//            url = source.readString();
//            thumbnail = source.readString();
//            title = source.readString();
//            view = source.readInt();
//            comment = source.readInt();
//            mylist = source.readInt();
//            length = source.readInt();
//            time = source.readLong();
//        }
	}
	private ArrayList<Video> mVideos;

	private Message mReplyOnFinished;
	private Message mReplyOnOccurredError;

	public RelatedVideoLoader(String videoNumber) {
		this(videoNumber, 1);
	}

	public RelatedVideoLoader(String videoNumber, int page) {
		mVideoNumber = videoNumber;
		mPage = page;
	}

	public int getTotalCount() {
		return mTotalCount;
	}
	public int getPageCount() {
		return mPageCount;
	}

	/**
	 * 完了時に、messageのobjにArrayList<Video>を渡して返す
	 * @param message
	 */
	public void registerMessageOnFinished(Message message) {
		mReplyOnFinished = message;
	}
	/**
	 * エラー発生時に、messageのobjにStringを渡して返す
	 * @param message
	 */
	public void registerMessageOnOccurredError(Message message) {
		mReplyOnOccurredError = message;
	}

	@Override
	protected HttpUriRequest createRequest() {
		HttpGet httpRequest = new HttpGet(
				"http://flapi.nicovideo.jp/api/getrelation?page=" + mPage
				+ "&video=" + mVideoNumber);
		return httpRequest;
	}

	@Override
	protected boolean createDataFromXml(String xmlBody) {
		ArrayList<Video> videos = new ArrayList<Video>();
		mVideos = videos;

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

			int next;
			String name = null;
			Video video = null;
			while ((next = pullParser.next()) != XmlPullParser.END_DOCUMENT) {
				if (DEBUG_LOGD_PARSE) {
					Log.d(LOG_TAG, Log.buf().append("next=").append(next).toString());
				}
				switch (next) {
				case XmlPullParser.START_TAG:
					name = pullParser.getName();
					if (DEBUG_LOGD_PARSE) {
						Log.d(LOG_TAG, Log.buf().append("<").append(name)
								.append(">").toString());
					}
					if ("related_video".equals(name)) {
						String status = pullParser.getAttributeValue(
								null, "status");
						if ("ok".equals(status)) {
							// OK
						} else if ("fail".equals(status)) {
							return false;
						} else {
							if (DEBUG_LOGD) {
								Log.d(LOG_TAG, Log.buf().append("related_video: status error=")
										.append(status).toString());
							}
							return false;
						}
					} else if ("video".equals(name)) {
//						assert video == null;
						video = new Video();
					} else {
						// その他のタグはとりあえず無視
					}
					break;
				case XmlPullParser.TEXT:
					if (name != null) {
						String text = pullParser.getText();
						try {
							if ("total_count".equals(name)) {
								if (mTotalCount != 0) {
									Log.w(LOG_TAG, "total_count duplicate?");
								}
								if (DEBUG_LOGD) {
									Log.d(LOG_TAG, Log.buf().append("total_count=")
											.append(text).toString());
								}
								mTotalCount = Integer.parseInt(text);
							} else if ("page_count".equals(name)) {
								if (mPageCount != 0) {
									Log.w(LOG_TAG, "page_count duplicate?");
								}
								if (DEBUG_LOGD) {
									Log.d(LOG_TAG, Log.buf().append("page_count=")
											.append(text).toString());
								}
								mPageCount = Integer.parseInt(text);
							} else if ("data_count".equals(name)) {
								if (mDataCount != 0) {
									Log.w(LOG_TAG, "data_count duplicate?");
								}
								if (DEBUG_LOGD) {
									Log.d(LOG_TAG, Log.buf().append("data_count=")
											.append(text).toString());
								}
								mDataCount = Integer.parseInt(text);
								videos.ensureCapacity(mDataCount);
							} else if ("url".equals(name)) {
								assert video != null;
								video.url = text;
							} else if ("thumbnail".equals(name)) {
								assert video != null;
								video.thumbnail = text;
							} else if ("title".equals(name)) {
								assert video != null;
								video.title = text;
							} else if ("view".equals(name)) {
								assert video != null;
								video.view = Integer.parseInt(text);
							} else if ("comment".equals(name)) {
								assert video != null;
								video.comment = Integer.parseInt(text);
							} else if ("mylist".equals(name)) {
								assert video != null;
								video.mylist = Integer.parseInt(text);
							} else if ("length".equals(name)) {
								assert video != null;
								video.length = Integer.parseInt(text);
							} else if ("time".equals(name)) {
								assert video != null;
								video.time = Long.parseLong(text);
							} else {
								// その他のタグはとりあえず無視
							}
						} catch (NumberFormatException e) {
							Log.d(LOG_TAG, Log.buf().append("parseInt failed:")
									.append(text).toString());
							// できる限り続行
						}
					}
					break;
				case XmlPullParser.END_TAG:
					name = pullParser.getName();
					if (DEBUG_LOGD_PARSE) {
						Log.d(LOG_TAG, Log.buf().append("</").append(name)
								.append(">").toString());
					}
					if ("video".equals(name)) {
						assert video != null;
						videos.add(video);

						if (DEBUG_LOGD) {
							Log.d(LOG_TAG, Log.buf().append("video:")
									.append(" url=").append(video.url)
									.append(" thumbnail=").append(video.thumbnail)
									.append(" title=").append(video.title)
									.append(" view=").append(video.view)
									.append(" comment=").append(video.comment)
									.append(" mylist=").append(video.mylist)
									.append(" length=").append(video.length)
									.append(" time=").append(video.time)
									.toString());
						}

						video = null;
					} else {
						// その他のタグはとりあえず無視
					}
					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);
		}
		return true;
	}

	@Override
	protected void dispatchOnFinished() {
		mReplyOnFinished.obj = mVideos;
		mReplyOnFinished.sendToTarget();
	}

	@Override
	protected void dispatchOnOccurredError(String errorMessage) {
		mReplyOnOccurredError.obj = errorMessage;
		mReplyOnOccurredError.sendToTarget();
	}

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

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