package jp.sourceforge.nicoro;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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.util.Xml;

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

public class ThumbInfo extends HttpXmlLoader {
	private static final boolean DEBUG_LOGD = Release.IS_DEBUG && true;
	private static final boolean DEBUG_LOGD_PARSE = Release.IS_DEBUG && true;
	
	private static final String PATTERN_LENGTH = "([0-9]+):([0-9]+)";
	
	private String mVideoNumber;

	private EventListener mEventListener = null;
	
	// XML解析データ
	private String mVideoId = null;
	private String mTitle = null;
	private String mDescription = null;
	private String mThumbnailUrl = null;
	private String mFirstRetrieve = null;
	private String mLength = null;
	private int mViewCounter = -1;
	private int mCommentNum = -1;
	private int mMylistCounter = -1;
	private String mLastResBody = null;
	private String mWatchUrl = null;
	private String mThumbType = null;
	private String mMovieType = null;
	
	private String mFormattedLengthForPlayer = null;
	private int mLengthBySeconds = -1;

	public ThumbInfo(String videoNumber) {
		mVideoNumber = videoNumber;
	}
	
	public int getViewCounter() {
		return mViewCounter;
	}
	public int getCommentNum() {
		return mCommentNum;
	}
	public int getMylistCounter() {
		return mMylistCounter;
	}
	public String getLength() {
		return mLength;
	}
	
	public String getFormattedLengthForPlayer() {
		if (mFormattedLengthForPlayer == null) {
			if (mLength == null) {
				return null;
			}
			Pattern pattern = Pattern.compile(PATTERN_LENGTH);
			Matcher matcher = pattern.matcher(mLength);
			if (matcher.find()) {
				final String minutes = matcher.group(1);
				final String seconds = matcher.group(2);
				final int minutesLength = minutes.length();
				final int secondsLength = seconds.length();
				if (minutesLength == 3 && secondsLength == 2) {
					// そのまま
					mFormattedLengthForPlayer = mLength;
				} else {
					StringBuilder builder = new StringBuilder(16);
					if (minutesLength == 1) {
						builder.append("00");
					}
					else if (minutesLength == 2) {
						builder.append('0');
					}
					builder.append(minutes).append(':');
					if (secondsLength == 1) {
						builder.append('0');
					}
					builder.append(seconds);
					mFormattedLengthForPlayer = builder.toString();
				}
			} else {
				// 異常時はそのまま
				Log.d(LOG_TAG, Log.buf().append("parse failed:")
						.append(mLength).toString());
				mFormattedLengthForPlayer = mLength;
			}
		}
		return mFormattedLengthForPlayer;
	}
	
	public int getLengthBySecond() {
		if (mLengthBySeconds < 0) {
			if (mLength == null) {
				return 0;
			}
			Pattern pattern = Pattern.compile(PATTERN_LENGTH);
			Matcher matcher = pattern.matcher(mLength);
			if (matcher.find()) {
				String minutes = matcher.group(1);
				String seconds = matcher.group(2);
				mLengthBySeconds = (Integer.parseInt(minutes) * 60
						+ Integer.parseInt(seconds));
			} else {
				// 異常時は0
				Log.d(LOG_TAG, Log.buf().append("parse failed:")
						.append(mLength).toString());
				mLengthBySeconds = 0;
			}
		}
		return mLengthBySeconds;
	}
	
	public String getTitle() {
		return mTitle;
	}

	public String getDescription() {
		return mDescription;
	}

	public String getMovieType() {
		return mMovieType;
	}

	@Override
	protected HttpUriRequest createRequest() {
		HttpGet httpRequest = new HttpGet(
				"http://www.nicovideo.jp/api/getthumbinfo/" + mVideoNumber);
		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_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 ("nicovideo_thumb_response".equals(name)) {
						String status = pullParser.getAttributeValue(
								null, "status");
						if ("ok".equals(status)) {
							// OK
						} else if ("fail".equals(status)) {
							return false;
						} else {
							Log.d(LOG_TAG, Log.buf().append("nicovideo_thumb_response: unknown attribute status=")
									.append(status).toString());
							return false;
						}
					} else {
						// その他のタグはとりあえず無視
					}
					break;
				case XmlPullParser.TEXT:
					if (name != null) {
						String text = pullParser.getText();
						try {
							if ("video_id".equals(name)) {
								mVideoId = text;
							} else if ("title".equals(name)) {
								mTitle = text;
							} else if ("description".equals(name)) {
								mDescription = text;
							} else if ("thumbnail_url".equals(name)) {
								mThumbnailUrl = text;
							} else if ("first_retrieve".equals(name)) {
								mFirstRetrieve = text;
							} else if ("length".equals(name)) {
								mLength = text;
							} else if ("view_counter".equals(name)) {
								mViewCounter = Integer.parseInt(text);
							} else if ("comment_num".equals(name)) {
								mCommentNum = Integer.parseInt(text);
							} else if ("mylist_counter".equals(name)) {
								mMylistCounter = Integer.parseInt(text);
							} else if ("last_res_body".equals(name)) {
								mLastResBody = text;
							} else if ("watch_url".equals(name)) {
								mWatchUrl = text;
							} else if ("thumb_type".equals(name)) {
								mThumbType = text;
							} else if ("movie_type".equals(name)) {
								mMovieType = 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());
					}
					name = null;
					// とりあえず無視
					break;
				default:
					break;
				}
			}
		} catch (XmlPullParserException e) {
			Log.d(LOG_TAG, e.getMessage(), e);
		} catch (IOException e) {
			Log.d(LOG_TAG, e.getMessage(), e);
		}
		
		if (DEBUG_LOGD) {
			Log.d(LOG_TAG, Log.buf().append("ThumbInfo:")
					.append(" video_id=").append(mVideoId)
					.append(" title=").append(mTitle)
					.append(" description=").append(mDescription)
					.append(" thumbnail_url=").append(mThumbnailUrl)
					.append(" first_retrieve=").append(mFirstRetrieve)
					.append(" length=").append(mLength)
					.append(" view_counter=").append(mViewCounter)
					.append(" comment_num=").append(mCommentNum)
					.append(" mylist_counter=").append(mMylistCounter)
					.append(" last_res_body=").append(mLastResBody)
					.append(" watch_url=").append(mWatchUrl)
					.append(" thumb_type=").append(mThumbType)
					.append(" movie_type=").append(mMovieType)
					.toString());
		}
		
		return true;
	}
	
	@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);
	}

	public void setEventListener(EventListener eventListener) {
		mEventListener = eventListener;
	}
	
	public interface EventListener {
		/**
		 * ファイル全体の読み込み完了
		 * @param streamLoader
		 */
		public void onFinished(ThumbInfo thumbInfo);
		/**
		 * エラー発生
		 * @param streamLoader
		 * @param errorMessage
		 */
		public void onOccurredError(ThumbInfo thumbInfo, String errorMessage);
	}
}
