package jp.sourceforge.nicoro;

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

import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.ListFragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;

import jp.gr.java_conf.shiseissi.commonlib.ViewUtil;
import jp.sourceforge.nicoro.RelatedVideoLoader.Video;
import jp.sourceforge.nicoro.StaticRes.string;

public class RelatedVideoFragment extends ListFragment
implements Handler.Callback {
//    private static final boolean DEBUG_LOGD = Release.IS_DEBUG & true;
    private static final boolean DEBUG_LOGV = Release.IS_DEBUG & false;

    private static final int MSG_ID_LOAD_FINISHED = 0;
    private static final int MSG_ID_LOAD_OCCURED_ERROR = 1;

    private static final String KEY_VIDEOS = "Videos";
    private static final String KEY_VIDEO_NUMBER = "VIDEO_NUMBER";

    private LayoutInflater mLayoutInflater;

    private String mVideoNumber;
    private int mPage;
    private RelatedVideoLoader mRelatedVideoLoader;
    private ArrayList<RelatedVideoLoader.Video> mVideos = new ArrayList<Video>();
    private RelatedVideoListAdapter mAdapter;

    private boolean mSavedInstanceState;

    private TextView mViewTitle;
    private ListEmptyProgressManager mEmptyProgress;

    private String mResStringInfoCountPlay;
    private String mResStringInfoCountComment;
    private String mResStringInfoCountMylist;
    private String mResStringUpload;

    private final HandlerWrapper mHandler = new HandlerWrapper(this);

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_ID_LOAD_FINISHED:
            @SuppressWarnings("unchecked")
            ArrayList<RelatedVideoLoader.Video> videos =
                (ArrayList<Video>) msg.obj;
            int totalCount = mRelatedVideoLoader.getTotalCount();
            if (totalCount == 0 && videos.size() == 0
                    && mVideos.size() == 0) {
                mEmptyProgress.showEmptyText();
            } else {
                mVideos.ensureCapacity(totalCount);
                mVideos.addAll(videos);

                if (mPage < mRelatedVideoLoader.getPageCount()) {
                    ++mPage;
                    createAndStartRelatedVideoLoader();
                } else {
                    mEmptyProgress.showEmptyText();
                    assert mPage == mRelatedVideoLoader.getPageCount();
                    mAdapter.setCount(mVideos.size());
                    mAdapter.notifyDataSetChanged();
                }
            }
            break;
        case MSG_ID_LOAD_OCCURED_ERROR:
            mEmptyProgress.showEmptyText();
            if (!mSavedInstanceState) {
                String errorMessage = (String) msg.obj;
                CloseDialogFragment.createErrorDialog(errorMessage,
                        false).show(getFragmentManager(),
                                getString(R.string.tag_close_dialog_fragment));
            }
            break;
        default:
            assert false : msg.what;
            break;
        }
        return true;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mSavedInstanceState = false;

        Resources res = getResources();
        mResStringInfoCountPlay = res.getString(R.string.info_count_play);
        mResStringInfoCountComment = res.getString(R.string.info_count_comment);
        mResStringInfoCountMylist = res.getString(R.string.info_count_mylist);
        mResStringUpload = res.getString(R.string.upload);

        if (savedInstanceState != null) {
            // Activityに追加される前にsetVideoNumber()が呼ばれたなら復帰しない
            if (mVideoNumber == null) {
                // FIXME ViewPagerのFragment復帰でどうしてもクラッシュすることがあるので、いったん実装を変える
//                ArrayList<Video> videos = savedInstanceState.getParcelableArrayList(
//                        KEY_VIDEOS);
                byte[] gzipBytes = savedInstanceState.getByteArray(KEY_VIDEOS);
                ArrayList<Video> videos = Util.inflateSerializable(gzipBytes);
                if (videos != null) {
                    mVideos.clear();
                    mVideos.addAll(videos);

                    String videoNumber = savedInstanceState.getString(KEY_VIDEO_NUMBER);
                    if (videoNumber != null) {
                        mVideoNumber = videoNumber;
                    }
                }
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mLayoutInflater = inflater;
        View v = inflater.inflate(R.layout.related_video_list, container, false);
        mViewTitle = ViewUtil.findViewById(v, R.id.list_title);
        mEmptyProgress = new ListEmptyProgressManager(v);
        if (mVideoNumber != null) {
            setTitleText();
        }

        if (savedInstanceState == null && mVideoNumber != null) {
            // Activityに追加される前にsetVideoNumber()が呼ばれた
            createAndStartRelatedVideoLoader();

            mEmptyProgress.showEmptyProgress();
        } else {
            mEmptyProgress.showEmptyText();
        }
        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        ListView listView = getListView();
        mAdapter = new RelatedVideoListAdapter();
        mAdapter.setCount(mVideos.size());
        setListAdapter(mAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Activity a = getActivity();
                if (a instanceof WebBrowserFragmentStarter) {
                    WebBrowserFragmentStarter starter =
                        (WebBrowserFragmentStarter) a;
                    String url = mVideos.get(position).url;

                    starter.startWebBrowserFragment(url);
                }
            }
        });
    }

    @Override
    public void onResume() {
        super.onResume();

        // オススメ表示のタイミングでもブラウザから情報取得
        updateVideoNumberByBrowser();
    }

    private void updateVideoNumberByBrowser() {
        WebBrowserFragment webBrowser = ViewUtil.findFragmentByTag(
                getFragmentManager(), string.tag_webbrowser_fragment);
        if (webBrowser == null) {
            // Intentにあればパラメータ取得
            Activity activity = getActivity();
            if (activity != null) {
                Intent intent = activity.getIntent();
                ListMenuView.updateFragmentRelatedVideo(intent, this);
            }
        } else {
            String videoNumber = webBrowser.getVideoId();
            if (!TextUtils.isEmpty(videoNumber)) {
                setVideoNumber(videoNumber);
            }
        }
    }

    @Override
    public void onDestroy() {
        // TODO: ANR対策の為に***Loader類のabort対応が必要
        if (mRelatedVideoLoader != null) {
            mRelatedVideoLoader.finish();
            mRelatedVideoLoader = null;
        }
        super.onDestroy();
        mHandler.release();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // FIXME ViewPagerのFragment復帰でどうしてもクラッシュすることがあるので、いったん実装を変える
//        outState.putParcelableArrayList(KEY_VIDEOS, mVideos);
        // サイズが大きい懸念があるので圧縮
        byte[] gzipBytes = Util.deflateSerializable(mVideos);
        outState.putByteArray(KEY_VIDEOS, gzipBytes);
        outState.putString(KEY_VIDEO_NUMBER, mVideoNumber);
        mSavedInstanceState = true;
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        if (!hidden) {
            // オススメ表示のタイミングでもブラウザから情報取得
            updateVideoNumberByBrowser();
        }
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (DEBUG_LOGV) {
                Log.v(LOG_TAG, "RelatedVideoActivity#finalize start");
            }
            super.finalize();
        } finally {
            if (mRelatedVideoLoader != null) {
                mRelatedVideoLoader.finish();
            }
            if (DEBUG_LOGV) {
                Log.v(LOG_TAG, "RelatedVideoActivity#finalize start");
            }
        }
    }

    private void createAndStartRelatedVideoLoader() {
        assert mHandler != null;
        RelatedVideoLoader loader = new RelatedVideoLoader(mVideoNumber, mPage);
        // TODO: ANR対策の為に***Loader類のabort対応が必要
        if (mRelatedVideoLoader != null) {
            mRelatedVideoLoader.finish();
        }
        mRelatedVideoLoader = loader;
        loader.registerMessageOnFinished(mHandler.obtainMessage(
                MSG_ID_LOAD_FINISHED));
        loader.registerMessageOnOccurredError(mHandler.obtainMessage(
                MSG_ID_LOAD_OCCURED_ERROR));
        loader.startLoad();
    }

    /**
     *
     * @param videoNumber vとidどちらでも可
     */
    public void setVideoNumber(String videoNumber) {
        if (!TextUtils.equals(videoNumber, mVideoNumber)) {
            mVideoNumber = videoNumber;
            mPage = 1;
            mVideos.clear();
            if (mAdapter != null) {
                mAdapter.setCount(0);
                mAdapter.notifyDataSetChanged();
            }

            if (isAdded()) {
                createAndStartRelatedVideoLoader();

                if (mEmptyProgress != null) {
                    mEmptyProgress.showEmptyProgress();
                }
            }

            if (mViewTitle != null) {
                setTitleText();
            }
        }
    }

    private void setTitleText() {
        String title = getString(R.string.title_related_video_fragment,
                mVideoNumber);
        mViewTitle.setText(title);
    }

    private class RelatedVideoListAdapter extends BaseAdapter {
        private int mCount = 0;
        private DateFormat mDateFormat = DateFormat.getDateTimeInstance(
                DateFormat.LONG, DateFormat.DEFAULT);
        private ThumbnailCacher mThumbnailCacher =
            NicoroApplication.getInstance(getActivity())
                .getThumbnailCacher();

        @Override
        public int getCount() {
            return mCount;
        }

        @Override
        public Object getItem(int position) {
            return mVideos.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view;
            ListItem listItem;
            if (convertView == null) {
                LayoutInflater inflater = mLayoutInflater;
                view = inflater.inflate(R.layout.related_video, parent, false);
                listItem = new ListItem();
                view.setTag(listItem);
                listItem.time = (VariableLabelView) view.findViewById(R.id.time);
                listItem.title = (VariableLabelView) view.findViewById(R.id.title);
                listItem.view = (VariableLabelView) view.findViewById(R.id.view);
                listItem.comment = (VariableLabelView) view.findViewById(R.id.comment);
                listItem.mylist = (VariableLabelView) view.findViewById(R.id.mylist);
                listItem.length = (VariableLabelView) view.findViewById(R.id.length);
                listItem.thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
            } else {
                view = convertView;
                listItem = (ListItem) convertView.getTag();
            }
            Video video = mVideos.get(position);

            listItem.time.getTextBuilderWithClear().append(mDateFormat.format(
                    new Date(video.time * 1000L)))
                    .append(" ").append(mResStringUpload);
            listItem.time.notifyUpdateText();

            listItem.title.setText(Util.convertHtmlEscapedCharacter(video.title));

            listItem.view.getTextBuilderWithClear().append(mResStringInfoCountPlay).append(video.view);
            listItem.view.notifyUpdateText();

            listItem.comment.getTextBuilderWithClear().append(mResStringInfoCountComment).append(video.comment);
            listItem.comment.notifyUpdateText();

            listItem.mylist.getTextBuilderWithClear().append(mResStringInfoCountMylist).append(video.mylist);
            listItem.mylist.notifyUpdateText();

            Util.appendPlayTime(listItem.length.getTextBuilderWithClear(),
                    video.length / 60, video.length % 60);
            listItem.length.notifyUpdateText();

            AsyncBitmapDrawable drawable;
            if (video.thumbnail == null) {
                drawable = null;
            } else {
                ViewGroup.LayoutParams params = listItem.thumbnail.getLayoutParams();
                Bitmap bitmap = mThumbnailCacher.getThumbnail(video.thumbnail);
                if (bitmap == null) {
                    drawable = new AsyncBitmapDrawable(params.width, params.height, true);
                    mThumbnailCacher.loadThumbnail(video.thumbnail,
                            new CallbackMessage<Bitmap, Void>(
                                    drawable.getHandler(), 0));
                } else {
                    drawable = new AsyncBitmapDrawable(bitmap,
                            params.width, params.height, true);
                }
            }
            listItem.thumbnail.setImageDrawable(drawable);

            return view;
        }

        public void setCount(int count) {
            boolean invalidate = (mCount != count);
            mCount = count;
            if (invalidate) {
                getListView().invalidateViews();
            }
        }
    }

    private static class ListItem {
        public VariableLabelView time;
        public VariableLabelView title;
        public VariableLabelView view;
        public VariableLabelView comment;
        public VariableLabelView mylist;
        public VariableLabelView length;
        public ImageView thumbnail;
    }
}
