/*
 * Copyright (C) 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.codeim.youliao.ui.base;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.codeim.youliao.R;
import com.codeim.youliao.TwitterApplication;
import com.codeim.youliao.app.Preferences;
import com.codeim.youliao.data.User;
import com.codeim.youliao.data.Tweet;
import com.codeim.youliao.db.StatusTable;
import com.codeim.youliao.fanfou.IDs;
import com.codeim.youliao.fanfou.Status;
import com.codeim.youliao.fanfou.Weibo;
import com.codeim.youliao.http.HttpException;
import com.codeim.youliao.location.LocationUtils;
import com.codeim.youliao.task.GenericTask;
import com.codeim.youliao.task.TaskAdapter;
import com.codeim.youliao.task.TaskListener;
import com.codeim.youliao.task.TaskManager;
import com.codeim.youliao.task.TaskParams;
import com.codeim.youliao.task.TaskResult;
import com.codeim.youliao.ui.module.FlingGestureListener;
import com.codeim.youliao.ui.module.MyActivityFlipper;
import com.codeim.youliao.ui.module.SimpleFeedback;
import com.codeim.youliao.ui.module.TweetAdapter;
import com.codeim.youliao.ui.module.NearbyUserArrayAdapter;
import com.codeim.youliao.util.DateTimeHelper;
import com.codeim.youliao.util.DebugTimer;
import com.hlidskialf.android.hardware.ShakeListener;
import com.markupartist.android.widget.PullToRefreshListView;
import com.markupartist.android.widget.PullToRefreshListView.OnRefreshListener;

public abstract class NearbyArrayBaseActivity extends NearbyListBaseActivity {
    static final String TAG = "NearbyArrayBaseActivity";
	
	protected static final String FEMALE = "0";
	protected static final String MALE = "1";
	protected static final String ALLUSER = "2";
	
	protected String mNameType = "";  // 不同页面的标记，用于刷新计时
	private int mRefreshFrequency = 0;
	protected String mSexType = ALLUSER;
	protected double mLat = 22.33;
	protected double mLng = 114.07;
	
	private SearchLocationObserver mSearchLocationObserver = new SearchLocationObserver();
	private LocationClient mLocClient;

    // Views.
    protected PullToRefreshListView mTweetList;  // 存放附近用户的列表
    protected NearbyUserArrayAdapter mUserListAdapter;
    protected View mListHeader;
    protected View mListFooter;
    protected TextView loadMoreBtn;
    protected ProgressBar loadMoreGIF;
    protected TextView loadMoreBtnTop;
    protected ProgressBar loadMoreGIFTop;

    protected static int lastPosition = 0;

    protected ShakeListener mShaker = null;
    
    // Tasks.
    protected TaskManager taskManager = new TaskManager();
    private GenericTask mRetrieveTask;
    private GenericTask mGetMoreTask;

    private int mRetrieveCount = 0;
    
    private ArrayList<com.codeim.youliao.data.User> allUserList;

    private TaskListener mRetrieveTaskListener = new TaskAdapter() {

        @Override
        public String getName() {
            return "RetrieveTask";
        }

        @Override
        public void onPostExecute(GenericTask task, TaskResult result) {
            // 刷新按钮停止旋转
            loadMoreGIF.setVisibility(View.GONE);
            mTweetList.onRefreshComplete();

            if (result == TaskResult.AUTH_ERROR) {
                mFeedback.failed("登录信息出错");
                logout();
            } else if (result == TaskResult.OK) {
                draw();
                if (task == mRetrieveTask) {
                    goTop();
                }
            } else if (result == TaskResult.IO_ERROR) {
                // FIXME: bad smell
                if (task == mRetrieveTask) {
                    mFeedback.failed(((RetrieveTask) task).getErrorMsg());
                } else if (task == mGetMoreTask) {
                    mFeedback.failed(((GetMoreTask) task).getErrorMsg());
                }
            } else {
                // do nothing
            }
            
            // DEBUG
            if (TwitterApplication.DEBUG) {
                DebugTimer.stop();
                Log.v("DEBUG", DebugTimer.getProfileAsString());
            }
        }

        @Override
        public void onPreExecute(GenericTask task) {
            mRetrieveCount = 0;
            mTweetList.prepareForRefresh();
            if (TwitterApplication.DEBUG) {
                DebugTimer.start();
            }
        }

        @Override
        public void onProgressUpdate(GenericTask task, Object param) {
            // Log.d(TAG, "onProgressUpdate");
            draw();
        }
    };

    // Refresh data at startup if last refresh was this long ago or greater.
    private static final long REFRESH_THRESHOLD = 5 * 60 * 1000;
    // Refresh followers if last refresh was this long ago or greater.
    private static final long FOLLOWERS_REFRESH_THRESHOLD = 12 * 60 * 60 * 1000;

	public abstract String getUserId();
	
    // abstract protected void markAllRead();
    // abstract protected Cursor fetchMessages();
    // public abstract int getDatabaseType();
    // public abstract String fetchMaxId();
    // public abstract String fetchMinId();
    // public abstract int addMessages(ArrayList<Tweet> tweets, boolean isUnread);
    // public abstract List<Status> getMessageSinceId(String maxId) throws HttpException;
	// public abstract List<Status> getMoreMessageFromId(String minId) throws HttpException;
	
	public abstract List<com.codeim.youliao.fanfou.User> getNearbyUser(int refreshFrequency, String sexType, 
	        double lat, double lng) throws HttpException;

    // public static final int CONTEXT_REPLY_ID = Menu.FIRST + 1;
    // public static final int CONTEXT_AT_ID = Menu.FIRST + 2;
    // public static final int CONTEXT_RETWEET_ID = Menu.FIRST + 3;
    // public static final int CONTEXT_DM_ID = Menu.FIRST + 4;
    // public static final int CONTEXT_MORE_ID = Menu.FIRST + 5;
    // public static final int CONTEXT_ADD_FAV_ID = Menu.FIRST + 6;
    // public static final int CONTEXT_DEL_FAV_ID = Menu.FIRST + 7;

    @Override
    protected void setupState() {
        setTitle(getActivityTitle());
        mTweetList = (PullToRefreshListView) findViewById(R.id.tweet_list);
        setupListHeader(true);
        // mTweetAdapter = new TweetCursorAdapter(this, cursor);
        // mTweetList.setAdapter(mTweetAdapter);
		mUserListAdapter = new NearbyUserArrayAdapter(this);
		mTweetList.setAdapter(mUserListAdapter);
		// mTweetList <- mUserListAdapter <- allUserList
		// ListView   <- Adapter          <- Data
		allUserList = new ArrayList<com.codeim.youliao.data.User>();
        // registerOnClickListener(mTweetList);
    }

    /**
     * 绑定listView底部 - 载入更多 NOTE: 必须在listView#setAdapter之前调用
     */
    protected void setupListHeader(boolean addFooter) {
        // Add Header to ListView
        // mListHeader = View.inflate(this, R.layout.listview_header, null);
        // mTweetList.addHeaderView(mListHeader, null, true);
    	mTweetList.setOnRefreshListener(new OnRefreshListener(){
    		@Override
    		public void onRefresh(){
    			doRetrieve();
    		}
    	});

        // Add Footer to ListView
        mListFooter = View.inflate(this, R.layout.listview_footer, null);
        mTweetList.addFooterView(mListFooter, null, true);
        
        // Find View
        loadMoreBtn = (TextView) findViewById(R.id.ask_for_more);
        loadMoreGIF = (ProgressBar) findViewById(R.id.rectangleProgressBar);
        loadMoreBtnTop = (TextView) findViewById(R.id.ask_for_more_header);
        loadMoreGIFTop = (ProgressBar) findViewById(R.id.rectangleProgressBar_header);
    }

    @Override
    protected void specialItemClicked(int position) {
        // 注意 mTweetAdapter.getCount 和 mTweetList.getCount的区别
        // 前者仅包含数据的数量（不包括foot和head），后者包含foot和head
        // 因此在同时存在foot和head的情况下，list.count = adapter.count + 2
        if (position == 0) {
            // 第一个Item(header)
            loadMoreGIFTop.setVisibility(View.VISIBLE);
            doRetrieve();
        } else if (position == mTweetList.getCount() - 1) {
            // 最后一个Item(footer)
            loadMoreGIF.setVisibility(View.VISIBLE);
            doGetMore();
        }
    }

    @Override
    protected int getLayoutId() {
        return R.layout.main;
    }

    @Override
    protected ListView getTweetList() {
        return mTweetList;
    }
	
	@Override
    protected TweetAdapter getTweetAdapter() {
        return mUserListAdapter;
    }

	/*
    @Override
    protected boolean useBasicMenu() {
        return true;
    }
	*/
	
	@Override
    protected User getContextItemTweet(int position) {
        position = position - 1;
        // 因为List加了Header和footer，所以要跳过第一个以及忽略最后一个
        if (position >= 0 && position < mUserListAdapter.getCount()) {
            User user = (User) mUserListAdapter.getItem(position);
            if (user == null) {
                return null;
            } else {
                return user;
            }
        } else {
            return null;
        }
    }

    @Override
    protected void updateTweet(Tweet tweet) {
        // TODO: updateTweet() 在哪里调用的? 目前尚只支持:
        // updateTweet(String tweetId, ContentValues values)
        // setFavorited(String tweetId, String isFavorited)
        // 看是否还需要增加updateTweet(Tweet tweet)方法

        // 对所有相关表的对应消息都进行刷新（如果存在的话）
        // getDb().updateTweet(TwitterDbAdapter.TABLE_FAVORITE, tweet);
        // getDb().updateTweet(TwitterDbAdapter.TABLE_MENTION, tweet);
        // getDb().updateTweet(TwitterDbAdapter.TABLE_TWEET, tweet);
    }

    @Override
    protected boolean _onCreate(Bundle savedInstanceState) {
        if (super._onCreate(savedInstanceState)) {

		    mLocClient = ((TwitterApplication)getApplication()).mLocationClient;  // 百度位置获取客户端
			
            boolean shouldRetrieve = false;
            // FIXME：该子类页面全部使用了这个统一的计时器，导致进入Mention等分页面后经常不会自动刷新
            long lastRefreshTime = mPreferences.getLong(mNameType + Preferences.LAST_TWEET_REFRESH_KEY, 0);
            long nowTime = DateTimeHelper.getNowTime();
            long diff = nowTime - lastRefreshTime;
            // Log.d(TAG, "Last refresh was " + diff + " ms ago.");
            if (diff > REFRESH_THRESHOLD) {
                shouldRetrieve = true;
            } else if (isTrue(savedInstanceState, SIS_RUNNING_KEY)) {
                // Check to see if it was running a send or retrieve task.
                // It makes no sense to resend the send request (don't want
                // dupes)
                // so we instead retrieve (refresh) to see if the message has
                // posted.
                // Log.d(TAG, "Was last running a retrieve or send task. Let's refresh.");
                shouldRetrieve = true;
            }

            if (shouldRetrieve) {
                doRetrieve();
            }

            goTop(); // skip the header

            // long lastFollowersRefreshTime = mPreferences.getLong(Preferences.LAST_FOLLOWERS_REFRESH_KEY, 0);
            // diff = nowTime - lastFollowersRefreshTime;
            // Log.d(TAG, "Last followers refresh was " + diff + " ms ago.");

            registerGestureListener();  // 手势识别
            registerShakeListener();  // 晃动刷新

            return true;
        } else {
            return false;
        }
    }

	@Override
    protected void onResume() {
        Log.d(TAG, "onResume.");
        if (lastPosition != 0) {
            mTweetList.setSelection(lastPosition);
        }
        if (mShaker != null){
        	mShaker.resume();
        }
        super.onResume();
        checkIsLogedIn();
		((TwitterApplication) getApplication()).requestLocationUpdates(mSearchLocationObserver);
		setLocationOption();  // 百度位置
		mLocClient.start();  // 百度位置
    }
	
	@Override
    protected void onPause() {
        Log.d(TAG, "onPause.");
        if (mShaker != null){
        	mShaker.pause();
        }
        super.onPause();
        lastPosition = mTweetList.getFirstVisiblePosition();
		((TwitterApplication) getApplication()).removeLocationUpdates(mSearchLocationObserver);
		mLocClient.stop();  // 百度位置
		mUserListAdapter.stopPlay();  // 停止语音播放
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        if (mRetrieveTask != null && mRetrieveTask.getStatus() == GenericTask.Status.RUNNING) {
            outState.putBoolean(SIS_RUNNING_KEY, true);
        }
    }

    @Override
    protected void onRestoreInstanceState(Bundle bundle) {
        super.onRestoreInstanceState(bundle);
        // mTweetEdit.updateCharsRemain();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy.");
        super.onDestroy();

        taskManager.cancelAll();

        // 刷新按钮停止旋转
        if (loadMoreGIF != null){
        	loadMoreGIF.setVisibility(View.GONE);
        }
        if (mTweetList != null){
        	mTweetList.onRefreshComplete();
        }
    }

    @Override
    protected void onRestart() {
        Log.d(TAG, "onRestart.");
        super.onRestart();
    }

    @Override
    protected void onStart() {
        Log.d(TAG, "onStart.");
        super.onStart();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "onStop.");
        super.onStop();
    }

    // UI helpers.

    @Override
    protected String getActivityTitle() {
        return null;
    }
	
	//设置相关参数
	private void setLocationOption() {
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true);  //打开gps
		option.setCoorType("bd0911");  //设置坐标类型
		option.setServiceName("com.baidu.location.service_v2.9");
		option.setPoiExtraInfo(true);
        option.setAddrType("all");
        option.setScanSpan(1000);
        option.setPriority(LocationClientOption.NetWorkFirst);  // LocationClientOption.GpsFirst 
		option.setPoiNumber(10);
		option.disableCache(true);		
		mLocClient.setLocOption(option);
	}

    public void draw() {
        //mTweetAdapter.refresh();
		mUserListAdapter.refresh(allUserList);
    }

    public void goTop() {
        Log.d(TAG, "goTop.");
        mTweetList.setSelection(1);
    }

    public void doRetrieve() {
        Log.d(TAG, "Attempting retrieve.");

        if (mRetrieveTask != null && mRetrieveTask.getStatus() == GenericTask.Status.RUNNING) {
            return;
        } else {
            mRetrieveTask = new RetrieveTask();
            mRetrieveTask.setFeedback(mFeedback);
            mRetrieveTask.setListener(mRetrieveTaskListener);
            mRetrieveTask.execute();

            // Add Task to manager
            taskManager.addTask(mRetrieveTask);
        }
    }
	
	public void doGetMore() {
        Log.d(TAG, "Attempting getMore.");

        if (mGetMoreTask != null && mGetMoreTask.getStatus() == GenericTask.Status.RUNNING) {
            return;
        } else {
            mGetMoreTask = new GetMoreTask();
            mGetMoreTask.setFeedback(mFeedback);
            mGetMoreTask.setListener(mRetrieveTaskListener);
            mGetMoreTask.execute();

            // Add Task to manager
            taskManager.addTask(mGetMoreTask);
        }
    }

    private class RetrieveTask extends GenericTask {
        private String _errorMsg;

        public String getErrorMsg() {
            return _errorMsg;
        }

        @Override
        protected TaskResult _doInBackground(TaskParams... params) {
            List<com.codeim.youliao.fanfou.User> usersList = null;
			mRefreshFrequency = 0;
			TwitterApplication twitterApplication = (TwitterApplication) getApplication();

            try {
			    double latitude;
				double longitude;
				/*
				Weibo.Location location = null;
				location = LocationUtils.createFoursquareLocation(twitterApplication.getLastKnownLocation());
				if (twitterApplication.getLastKnownLocation() != null) {
				    latitude = location.getLat();
				    longitude = location.getLon();
				} else {
				    BDLocation BDLoc = twitterApplication.getBDLocation();
					while (BDLoc == null) {
					    BDLoc = twitterApplication.getBDLocation();
					}
					latitude = BDLoc.getLatitude();
					longitude = BDLoc.getLongitude();
				}
				*/
				
				BDLocation BDLoc = twitterApplication.getBDLocation();
				while (BDLoc == null || (BDLoc.getLatitude() == 0 && BDLoc.getLongitude() == 0)) {
					BDLoc = twitterApplication.getBDLocation();
				}
				latitude = BDLoc.getLatitude();
				longitude = BDLoc.getLongitude();
				// Toast.makeText(getApplicationContext(), "latitude = " + latitude + " , longitude = " + longitude, Toast.LENGTH_SHORT).show();
				
				mLat = latitude;
				mLng = longitude;
                //statusList = getMessageSinceId(maxId);
            	usersList = getNearbyUser(mRefreshFrequency, mSexType, mLat, mLng);
            } catch (HttpException e) {
                Log.e(TAG, e.getMessage(), e);
                _errorMsg = e.getMessage();
                return TaskResult.IO_ERROR;
            }

            publishProgress(SimpleFeedback.calProgressBySize(40, 20, usersList));
			allUserList.clear();
			for (com.codeim.youliao.fanfou.User user : usersList) {
				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}
				// Log.d(TAG, "User: " + user.toString());
				User u = User.create(user);
				allUserList.add(u);
				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}
			}

            return TaskResult.OK;
        }
    }

    // GET MORE TASK
    private class GetMoreTask extends GenericTask {
        private String _errorMsg;

        public String getErrorMsg() {
            return _errorMsg;
        }

        @Override
        protected TaskResult _doInBackground(TaskParams... params) {
            List<com.codeim.youliao.fanfou.User> usersList = null;
			mRefreshFrequency = mRefreshFrequency + 1;
			TwitterApplication twitterApplication = (TwitterApplication) getApplication();

            try {
			    double latitude;
				double longitude;
				Weibo.Location location = null;
				location = LocationUtils.createFoursquareLocation(twitterApplication.getLastKnownLocation());
				if (twitterApplication.getLastKnownLocation() != null) {
				    latitude = location.getLat();
				    longitude = location.getLon();
				} else {
				    BDLocation BDLoc = twitterApplication.getBDLocation();
					while (BDLoc == null) {
					    BDLoc = twitterApplication.getBDLocation();
					}
					latitude = BDLoc.getLatitude();
					longitude = BDLoc.getLongitude();
				}
				mLat = latitude;
				mLng = longitude;
                //statusList = getMessageSinceId(maxId);
            	usersList = getNearbyUser(mRefreshFrequency, mSexType, mLat, mLng);
            } catch (HttpException e) {
                Log.e(TAG, e.getMessage(), e);
                _errorMsg = e.getMessage();
                return TaskResult.IO_ERROR;
            }

            publishProgress(SimpleFeedback.calProgressBySize(40, 20, usersList));
			for (com.codeim.youliao.fanfou.User user : usersList) {
				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}
				User u = User.create(user);
				allUserList.add(u);
				if (isCancelled()) {
					return TaskResult.CANCELLED;
				}
			}

            return TaskResult.OK;
        }
    }
    
    //////////////////// Gesture test /////////////////////////////////////
    private static boolean useGestrue;
    {
        useGestrue = TwitterApplication.mPref.getBoolean(Preferences.USE_GESTRUE, false);
        if (useGestrue) {
            Log.v(TAG, "Using Gestrue!");
        } else {
            Log.v(TAG, "Not Using Gestrue!");
        }
    }
    
    //////////////////// Gesture test /////////////////////////////////////
    private static boolean useShake;
    {
        useShake = TwitterApplication.mPref.getBoolean(Preferences.USE_SHAKE, false);
        if (useShake) {
            Log.v(TAG, "Using Shake to refresh!");
        } else {
            Log.v(TAG, "Not Using Shake!");
        }
    }
    
    
    protected FlingGestureListener myGestureListener = null;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (useGestrue && myGestureListener != null) {
            return myGestureListener.getDetector().onTouchEvent(event);
        }
        return super.onTouchEvent(event);
    }

    // use it in _onCreate
    private void registerGestureListener() {
        if (useGestrue) {
            myGestureListener = new FlingGestureListener(this, MyActivityFlipper.create(this));
            getTweetList().setOnTouchListener(myGestureListener);
        }
    }
    
    // use it in _onCreate
    private void registerShakeListener() {
    	if (useShake){
	    	mShaker = new ShakeListener(this);
	    	mShaker.setOnShakeListener(new ShakeListener.OnShakeListener() {
				
				@Override
				public void onShake() {
					Log.v(TAG, "onShake");
					doRetrieve();
				}
			});
    	}
	}

    /** 
     * This is really just a dummy observer to get the GPS running
     * since this is the new splash page. After getting a fix, we
     * might want to stop registering this observer thereafter so
     * it doesn't annoy the user too much.
     */
    private class SearchLocationObserver implements Observer {
        @Override
        public void update(Observable observable, Object data) {
        }
    }    
}