public class ChhApplication extends Application {
    private static ChhApplication instance;
    private String formHash;

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

        instance = this;

        LogMessage.setDebug(BuildConfig.DEBUG);

        initImageLoader();

        setupUpdate();
    }

    private void setupUpdate() {
        UmengUpdateAgent.setUpdateAutoPopup(false);
        UmengUpdateAgent.setUpdateOnlyWifi(false);
    }


    public String getFormHash() {
        return formHash;
    }

    public void setFormHash(String formHash) {
        this.formHash = formHash;
    }

    // 初始化ImageLoader
    private void initImageLoader() {
        DisplayImageOptions defaultDisplayImageOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .showImageForEmptyUri(R.drawable.logo)
                .showImageOnFail(R.drawable.logo)
                .showImageOnLoading(R.drawable.logo)
                // .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
                .build();

        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(40, TimeUnit.SECONDS)
                .cookieJar(new JavaNetCookieJar(WebViewCookieHandler.getInstance()))
                .build();
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
                .denyCacheImageMultipleSizesInMemory()
                .defaultDisplayImageOptions(defaultDisplayImageOptions)
                .imageDownloader(new OkHttpImageDownloader(this, client))
                .build();
        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config);

    }

    static class OkHttpImageDownloader extends BaseImageDownloader {


        private OkHttpClient client;


        public OkHttpImageDownloader(Context context, OkHttpClient client) {
            super(context);
            this.client = client;
        }


        @Override
        protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
            Request request = new Request.Builder().url(imageUri).build();
            ResponseBody responseBody = client.newCall(request).execute().body();
            InputStream inputStream = responseBody.byteStream();
            int contentLength = (int) responseBody.contentLength();
            return new ContentLengthInputStream(inputStream, contentLength);
        }
    }

    public static ChhApplication getInstance() {
        return instance;
    }

    /**
     * 是否登录
     *
     * @return
     */
    public boolean isLogin() {
        return !TextUtils.isEmpty(formHash);
    }


} public class ChhApi {
    protected static final String TAG = "ChhApi";
    private Mode mMode;

    public ChhApi() {
        this(Mode.MOBILE);
    }

    public ChhApi(Mode mode) {
        this.mMode = mode;
    }

    /**
     * 获取版块列表
     */
    public static ApiRequest<List<PlateGroup>> getPlateGroups() {

        return new RequestBuilder<List<PlateGroup>>()
                .url(Constants.BASE_URL + "forum.php?forumlist=1&mobile=1")
                .shouldCache()
                .objectParser(new ObjectParser<List<PlateGroup>>() {
                    @Override
                    public List<PlateGroup> parse(String content) {
                        return HtmlParse.parsePlateGroupList(content);
                    }
                })
                .build();
    }

    /**
     * 获取用户信息
     */
    public static ApiRequest<User> getUserInfo() {
        return new RequestBuilder<User>()
                .url(Constants.BASE_URL + "home.php?mod=space&mobile=2")
                .shouldCache()
                .objectParser(new ObjectParser<User>() {
                    @Override
                    public User parse(String content) {
                        return HtmlParse.parseUserInfo(content);
                    }
                })
                .build();
    }

    /**
     * 获取帖子列表
     *
     * @param url  版块链接
     * @param page 页码
     */
    public static ApiRequest<ThreadListWrap> getThreadList(String url, final int page, String orderBy) {
        return new RequestBuilder<ThreadListWrap>()
                .url(url)
                .putParameter("page", page)
                .putParameterIf(!TextUtils.isEmpty(orderBy), "orderby", orderBy)
                .shouldCache(page == 1)
                .objectParser(new ObjectParser<ThreadListWrap>() {
                    @Override
                    public ThreadListWrap parse(String content) {
                        return HtmlParse.parseThreadList(content, page == 1);
                    }
                })
                .build();
    }

    /**
     * 获取回复列表
     *
     * @param thread 帖子
     * @param page   页码
     */
    public static ApiRequest<PostListWrap> getPostList(Thread thread, int page) {
        return new RequestBuilder<PostListWrap>()
                .url(thread.getUrl())
                .shouldCache()
                .putParameter("page", page)
                .putParameter("mobile", 2)// 回帖列表使用触屏版来解析
                .objectParser(new ObjectParser<PostListWrap>() {
                    @Override
                    public PostListWrap parse(String content) {
                        return HtmlParse.parsePostList(content);
                    }
                })
                .build();
    }

    /**
     * 回复主贴
     *
     * @param fid
     * @param tid
     * @param formhash
     * @param message
     */
    public static ApiRequest<ReplyResult> reply(String fid, String tid, String formhash, final String message) {
        return new RequestBuilder<ReplyResult>()
                .url(Constants.BASE_URL + "forum.php?mod=post&action=reply&replysubmit=yes&mobile=2")
                .method(Request.Method.POST)
                .putParameter("message", message)
                .putParameter("fid", fid)
                .putParameter("tid", tid)
                .putParameter("formhash", formhash)
                .objectParser(new ObjectParser<ReplyResult>() {
                    @Override
                    public ReplyResult parse(String content) {
                        ReplyResult result = new ReplyResult();

                        String messagetext = HtmlParse.parseMessageText(content);
                        if (messagetext != null) {
                            result.setMessage(messagetext);
                            return result;
                        }
                        result.setPostListWrap(HtmlParse.parsePostList(content));
                        return result;
                    }
                })
                .build();

        //String url = Constants.BASE_URL + "forum.php?mod=post&action=reply&replysubmit=yes&mobile=2";
        //RequestParams param = new RequestParams();
        //param.add("message", message);
        //param.add("fid", fid);
        //param.add("tid", tid);
        //param.add("formhash", formhash);
        //getAsyncHttpClient().post(url, param, new ApiResponsHandler<PostListWrap>(apiCallBack) {
        //
        //    @Override
        //    public PostListWrap parseResponse(String responseString) {
        //        LogMessage.i(TAG + "#quotrReply", responseString);
        //        String messagetext = HtmlParse.parseMessageText(responseString);
        //        if (messagetext != null) {
        //            sendFailureMessage(0, null, messagetext.getBytes(), new Throwable(messagetext));
        //            return null;
        //        }
        //        return HtmlParse.parsePostList(responseString);
        //    }
        //});
    }

    /**
     * 引用回复
     *
     * @param quoteReply
     */
    public static ApiRequest<ReplyResult> quotrReply(PrepareQuoteReply quoteReply) {
        return new RequestBuilder<ReplyResult>()
                .url(quoteReply.getUrl())
                .method(Request.Method.POST)
                .putParameter("formhash", quoteReply.getFormhash())
                .putParameter("message", quoteReply.getMessage())
                .putParameter("noticeauthor", quoteReply.getNoticeauthor())
                .putParameter("noticeauthormsg", quoteReply.getNoticeauthormsg())
                .putParameter("noticetrimstr", quoteReply.getNoticetrimstr())
                .putParameter("posttime", quoteReply.getPosttime())
                .putParameter("replysubmit", quoteReply.getReplysubmit())
                .putParameter("reppid", quoteReply.getReppid())
                .putParameter("reppost", quoteReply.getReppost())
                .objectParser(new ObjectParser<ReplyResult>() {
                    @Override
                    public ReplyResult parse(String content) {
                        ReplyResult result = new ReplyResult();

                        String messagetext = HtmlParse.parseMessageText(content);
                        if (messagetext != null) {
                            result.setMessage(messagetext);
                            return result;
                        }
                        result.setPostListWrap(HtmlParse.parsePostList(content));
                        return result;
                    }
                })
                .build();

        //RequestParams params = new RequestParams();
        //params.add("formhash", quoteReply.getFormhash());
        //params.add("message", quoteReply.getMessage());
        //params.add("noticeauthor", quoteReply.getNoticeauthor());
        //params.add("noticeauthormsg", quoteReply.getNoticeauthormsg());
        //params.add("noticetrimstr", quoteReply.getNoticetrimstr());
        //params.add("posttime", quoteReply.getPosttime());
        //params.add("replysubmit", quoteReply.getReplysubmit());
        //params.add("reppid", quoteReply.getReppid());
        //params.add("reppost", quoteReply.getReppost());
        //getAsyncHttpClient().post(quoteReply.getUrl(), params, new ApiResponsHandler<PostListWrap>(apiCallBack) {
        //
        //    @Override
        //    public PostListWrap parseResponse(String responseString) {
        //        LogMessage.i(TAG + "#quotrReply", responseString);
        //        String messagetext = HtmlParse.parseMessageText(responseString);
        //        if (messagetext != null) {
        //            sendFailureMessage(0, null, messagetext.getBytes(), new Throwable(messagetext));
        //            return null;
        //        }
        //        return HtmlParse.parsePostList(responseString);
        //    }
        //});
    }

    /**
     * 引用回复的请求表单准备
     *
     * @param url
     */
    public static ApiRequest<PrepareQuoteReply> prepareQuoteReply(String url) {
        return new RequestBuilder<PrepareQuoteReply>()
                .url(url)
                .objectParser(new ObjectParser<PrepareQuoteReply>() {
                    @Override
                    public PrepareQuoteReply parse(String content) {
                        return HtmlParse.parsePrepareQuoteReply(content);
                    }
                })
                .build();
    }

    /**
     * 获取图片列表
     *
     * @param url
     */
    public static ApiRequest<AlbumWrap> getAlbum(String url) {
        return new RequestBuilder<AlbumWrap>()
                .url(url)
                .objectParser(new ObjectParser<AlbumWrap>() {
                    @Override
                    public AlbumWrap parse(String content) {
                        return HtmlParse.parseAubum(content);
                    }
                })
                .build();
        //getAsyncHttpClient().get(url, new ApiResponsHandler<AlbumWrap>(apiCallBack) {
        //
        //    @Override
        //    public AlbumWrap parseResponse(String responseString) {
        //        LogMessage.i(TAG + "#getAlbum", responseString);
        //
        //        return HtmlParse.parseAubum(responseString);
        //    }
        //});

    }

    /**
     * 收藏版块
     *
     * @param id
     * @param formhash
     * @param apiCallBack
     */
    public static final int TYPE_FORUM = 0;
    public static final int TYPE_THREAD = 1;

    public static ApiRequest<String> favorite(String id, int type, String formhash) {
        return new RequestBuilder<String>()
                .method(Request.Method.POST)
                .url(Constants.BASE_URL + "home.php")
                .putParameter("mod", "spacecp")
                .putParameter("ac", "favorite")
                .putParameterIf(type == TYPE_FORUM, "type", "forum")
                .putParameterIf(type == TYPE_THREAD, "type", "thread")
                .putParameter("id", id)
                .putParameter("formhash", formhash)
                .putParameter("mobile", "yes")
                .objectParser(new ObjectParser<String>() {
                    @Override
                    public String parse(String content) {
                        return HtmlParse.parseMessageText(content);
                    }
                })
                .build();
    }

    public static ApiRequest<String> deleteFavorite(String favid, String formhash) {
        return new RequestBuilder<String>()
                .url(Constants.BASE_URL + "home.php")
                .method(Request.Method.POST)
                .putParameter("mod", "spacecp")
                .putParameter("ac", "favorite")
                .putParameter("op", "delete")
                .putParameter("favid", favid)
                .putParameter("type", "forum")
                .putParameter("formhash", formhash)
                .putParameter("mobile", "yes")
                .putParameter("deletesubmit", "true")
                .objectParser(new ObjectParser<String>() {
                    @Override
                    public String parse(String content) {
                        return HtmlParse.parseMessageText(content);
                    }
                })
                .build();

        //String url = Constants.BASE_URL + "home.php";
        //RequestParams params = new RequestParams();
        //params.add("mod", "spacecp");
        //params.add("ac", "favorite");
        //params.add("op", "delete");
        //params.add("favid", favid);
        //params.add("type", "forum");
        //params.add("formhash", formhash);
        //params.add("mobile", "yes");
        //params.add("deletesubmit", "true");
        //getAsyncHttpClient().post(url, params, new ApiResponsHandler<String>(apiCallBack) {
        //
        //    @Override
        //    public String parseResponse(String responseString) {
        //        return HtmlParse.parseMessageText(responseString);
        //    }
        //});
    }

    public void checkAppUpdate(ApiCallBack<AppUpdate> apiCallBack) {
        //new AsyncHttpClient().get("http://fir.im/api/v2/app/version/548cf2e12b17bad661000596",
        //        new ApiResponsHandler<AppUpdate>(apiCallBack) {
        //
        //            @Override
        //            public AppUpdate parseResponse(String responseString) {
        //                return new AppUpdate().fromJson(responseString);
        //            }
        //        });
    }

    //private AsyncHttpClient getAsyncHttpClient() {
    //    if (mAsyncHttpClient == null) {
    //        mAsyncHttpClient = new AsyncHttpClient();
    //        mAsyncHttpClient.setTimeout(30 * 1000);
    //        mAsyncHttpClient.addHeader("Cookie", CookieManager.getInstance().getCookie(Constants.BASE_URL));
    //        mAsyncHttpClient.setCookieStore(new PersistentCookieStore(ChhApplication.getInstance()));
    //        mAsyncHttpClient.addHeader("Content-Type", "application/x-www-form-urlencoded");
    //    }
    //    return mAsyncHttpClient;
    //}
} public abstract class ApiCallBack<T> {
    public void onSuccess(T result) { }

    public void onFailure(Throwable error, String content) { }

    public void onFinish() { }

    public void onStart() { }

    public void onCache(T result) { }

    void onCancel() { }

} public class ApiHelper {
    // TODO: 15/11/21 queue
    static {
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .cookieJar(new JavaNetCookieJar(WebViewCookieHandler.getInstance()))
                .build();
        OkHttpStack stack = new OkHttpStack(new OkUrlFactory(okHttpClient));
        requestQueue = Volley.newRequestQueue(ChhApplication.getInstance(), stack);
    }

    private static RequestQueue requestQueue;

    /**
     * 请求接口并回调
     *
     * @param request  请求
     * @param callBack 回调
     * @param <T>      响应数据类型
     */
    public static <T> void requestApi(ApiRequest<T> request, ApiCallBack<T> callBack) {
        request.setCallback(callBack);
        requestQueue.add(request);
    }

    /**
     * 请求接口不进行回调
     *
     * @param request 请求
     * @param <T>     响应数据类型
     */
    public static <T> void requestApi(ApiRequest<T> request) {
        requestQueue.add(request);
    }

    /**
     * 同步请求接口
     *
     * @param request 请求
     * @param <T>     解析类型
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     * @throws TimeoutException
     */
    public static <T> T requestSyncApi(ApiRequest<T> request) throws InterruptedException, ExecutionException, TimeoutException {
        ApiFuture<T> apiFuture = ApiFuture.newFuture();
        request.setCallback(apiFuture);
        requestQueue.add(request);
        return apiFuture.get(request.getTimeoutMs(), TimeUnit.MILLISECONDS);
    }

    /**
     * 取消所有请求
     */
    public static void cancelAll() {
        requestQueue.cancelAll(new RequestQueue.RequestFilter() {
            @Override
            public boolean apply(Request<?> request) {
                return true;
            }
        });
    }

    /**
     * 取消所有标记为tag的请求
     *
     * @param tag
     */
    public static void cancelAll(Object tag) {
        requestQueue.cancelAll(tag);
    }
} public class Plate extends BaseBean {
    private String title;
    private String url;
    private String xg1;// 今日帖数
    private String fid;// 版块id
    private String favoriteId;
    private boolean isSubPlate;// 是否是子版块

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getXg1() {
        return xg1 == null ? "(0)" : xg1;
    }

    public void setXg1(String xg1) {
        this.xg1 = xg1;
    }

    @Override
    public String toString() {
        return title;
    }

    public boolean isSubPlate() {
        return isSubPlate;
    }

    public void setSubPlate(boolean isSubPlate) {
        this.isSubPlate = isSubPlate;
    }

    public boolean isFavorite() {
        return favoriteId != null;
    }

    public String getFavoriteId() {
        return favoriteId;
    }

    public void setFavoriteId(String favoriteId) {
        this.favoriteId = favoriteId;
    }

    public void setFid(String fid) {
        this.fid = fid;
    }

    public String getFid() {
        if (fid == null) {
            fid = new UrlParamsMap(url).get("fid");
        }
        return fid;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Plate) {
            if (((Plate) o).getFid().equals(this.getFid())) {
                return true;
            }
        }
        return false;
    }
} public class Post extends BaseBean {
    private String avatarUrl;
    private String replyUrl;
    private String content;
    private String authi;// 名字，楼层，时间 html
    private String imgList;// 图片附件列表
    private List<String> images;//图片列表

    public String getAvatarUrl() {
        return avatarUrl;
    }

    public void setAvatarUrl(String avatarUrl) {
        this.avatarUrl = avatarUrl;
    }

    public String getReplyUrl() {
        return replyUrl;
    }

    public void setReplyUrl(String replyUrl) {
        this.replyUrl = replyUrl;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getAuthi() {
        return authi;
    }

    public void setAuthi(String authi) {
        this.authi = authi;
    }

    public String getImgList() {
        return imgList;
    }

    public void setImgList(String imgList) {
        this.imgList = imgList;
    }

    @Override
    public String toString() {
        return "Post [avatarUrl=" + avatarUrl + ", replyUrl=" + replyUrl + ", content=" + content + ", authi=" + authi + "]";
    }

    public List<String> getImages() {
        return images;
    }

    public void setImages(List<String> images) {
        this.images = images;
    }
} public class PostListWrap extends BaseBean {
    private String title;
    private List<Post> posts;
    private int totalPage;
    private int curPage;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public List<Post> getPosts() {
        return posts;
    }

    public void setPosts(List<Post> posts) {
        this.posts = posts;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int size() {
        return posts != null ? posts.size() : 0;
    }
} public class PrepareQuoteReply {
    String url;
    String quoteBody;
    String formhash;
    String message;
    String noticeauthor;
    String noticeauthormsg;
    String noticetrimstr;
    String posttime;
    String replysubmit = "yes";
    String reppid;
    String reppost;

    /*
     * 验证码相关
     * String seccodehash;
     * String seccodeverify;
     */

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getQuoteBody() {
        return quoteBody;
    }

    public void setQuoteBody(String quoteBody) {
        this.quoteBody = quoteBody;
    }

    public String getFormhash() {
        return formhash;
    }

    public void setFormhash(String formhash) {
        this.formhash = formhash;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getNoticeauthor() {
        return noticeauthor;
    }

    public void setNoticeauthor(String noticeauthor) {
        this.noticeauthor = noticeauthor;
    }

    public String getNoticeauthormsg() {
        return noticeauthormsg;
    }

    public void setNoticeauthormsg(String noticeauthormsg) {
        this.noticeauthormsg = noticeauthormsg;
    }

    public String getNoticetrimstr() {
        return noticetrimstr;
    }

    public void setNoticetrimstr(String noticetrimstr) {
        this.noticetrimstr = noticetrimstr;
    }

    public String getPosttime() {
        return posttime;
    }

    public void setPosttime(String posttime) {
        this.posttime = posttime;
    }

    public String getReppid() {
        return reppid;
    }

    public void setReppid(String reppid) {
        this.reppid = reppid;
    }

    public String getReplysubmit() {
        return replysubmit;
    }

    public String getReppost() {
        return reppost;
    }

    public void setReppost(String reppost) {
        this.reppost = reppost;
    }

    @Override
    public String toString() {
        return "PrepareQuoteReply [url=" + url + ", quoteBody=" + quoteBody + ", formhash=" + formhash + ", message=" + message
                + ", noticeauthor=" + noticeauthor + ", noticeauthormsg=" + noticeauthormsg + ", noticetrimstr=" + noticetrimstr
                + ", posttime=" + posttime + ", replysubmit=" + replysubmit + ", reppid=" + reppid + ", reppost=" + reppost + "]";
    }

} public class Thread extends BaseBean {
    String title;
    String url;
    String by;
    String timeAndCount;
    String date;
    String count;
    String imgSrc;
    int titleColor;
    String tid;// 帖子id

    public String getImgSrc() {
        return imgSrc;
    }

    public void setImgSrc(String imgSrc) {
        this.imgSrc = imgSrc;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getBy() {
        return by;
    }

    public void setBy(String by) {
        this.by = by;
    }

    public String getDate() {
        calcDateAndCount();
        return date;
    }

    private void calcDateAndCount() {
        if (date == null || count == null) {
            timeAndCount = timeAndCount.trim();
            try {
                String[] s = timeAndCount.split("回");
                date = s[0];
                count = s[1];
            } catch (Exception e) {
                date = timeAndCount;
                count = "0";
            }
        }
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getCount() {
        calcDateAndCount();
        return count;
    }

    public void setCount(String count) {
        this.count = count;
    }

    public void setTimeAndCount(String timeAndCount) {
        this.timeAndCount = timeAndCount;
    }

    public int getTitleColor() {
        return titleColor;
    }

    public void setTitleColor(int titleColor) {
        this.titleColor = titleColor;
    }

    @Override
    public String toString() {
        return "Thread [title=" + title + ", url=" + url + ", by=" + by + ", timeAndCount=" + timeAndCount + "]";
    }

    public String getTid() {
        if (tid == null) {
            tid = new UrlParamsMap(url).get("tid");
        }
        return tid;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (getTid() == null) return false;

        Thread thread = (Thread) o;

        UrlParamsMap l = new UrlParamsMap(url);
        UrlParamsMap r = new UrlParamsMap(thread.getUrl());

        return (getTid().equals(r.get("tid")))
                && ("viewthread".equals(l.get("mod")) && "viewthread".equals(r.get("mod")))
                ;

    }

    @Override
    public int hashCode() {
        return getTid() != null ? getTid().hashCode() : 0;
    }
} public class Constants {
    /**
     * 论坛地址，注意结尾的斜杠
     */
    public static String BASE_URL = GlobalSetting.getForumAddress();
    //显示头像
    public static DisplayImageOptions avatarDisplayOption = new DisplayImageOptions.Builder()
            .cacheInMemory(true).cacheOnDisc(true)
            .showImageForEmptyUri(R.drawable.noavatar)
            .showImageOnFail(R.drawable.noavatar)
            .showImageOnLoading(R.drawable.noavatar)
            .build();
} public class PostPageAdapter extends FragmentPagerAdapter {
    private Thread thread;
    private int size = 1;
    private WeakHashMap<Integer, PostListFragment> postFragments;

    public PostPageAdapter(FragmentManager fm, Thread thread) {
        super(fm);
        this.thread = thread;
        postFragments = new WeakHashMap<Integer, PostListFragment>();
    }

    @Override
    public Fragment getItem(int i) {
        PostListFragment instance = PostListFragment.getInstance(i + 1, thread);
        postFragments.put(i, instance);
        return instance;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
        notifyDataSetChanged();
    }

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

    public PostListFragment getPostFragment(int i) {
        return postFragments.get(i);
    }
} public class MySlidingUpPanelLayout extends SlidingUpPanelLayout {
    public MySlidingUpPanelLayout(Context context) {
        super(context);
    }

    public MySlidingUpPanelLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MySlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public HookDispatchTouchEvent getHookDispatchTouchEvent() {
        return hookDispatchTouchEvent;
    }

    public void setHookDispatchTouchEvent(HookDispatchTouchEvent hookDispatchTouchEvent) {
        this.hookDispatchTouchEvent = hookDispatchTouchEvent;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean hookRet = false;
        if (hookDispatchTouchEvent != null) {
            hookRet = hookDispatchTouchEvent.dispatchTouchEvent(ev);
        }
        try {
            return hookRet || super.dispatchTouchEvent(ev);
        } catch (ArrayIndexOutOfBoundsException e) {}
        return false;
    }

    public boolean callSuperDispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    HookDispatchTouchEvent hookDispatchTouchEvent;

    public void expandPanel() {
        setPanelState(PanelState.EXPANDED);
    }

    public boolean isPanelExpanded() {
        return PanelState.EXPANDED.equals(getPanelState());
    }

    public void collapsePanel() {
        setPanelState(PanelState.COLLAPSED);
    }

    public static interface HookDispatchTouchEvent {
        boolean dispatchTouchEvent(MotionEvent ev);
    }
} @EFragment(R.layout.fragment_fast_reply)
public class FastReplyFragment extends BaseFragment implements OnClickListener {
    @ViewById(R.id.editText_fast_reply)
    EditText editTextFastReply;

    @ViewById(R.id.button_reply_send)
    View btnReplySend;

    // @ViewById(R.id.layout_float_label)
    // FloatLabelLayout floatLabelLayout;

    @ViewById(R.id.textView_hint)
    TextView textViewHint;

    @ViewById(R.id.layout_smile)
    View layoutSmile;

    @ViewById(R.id.button_smile)
    View viewSmile;

    // 当前需要回复的版块
    Plate mPlate;

    // 当前需要回帖的贴子
    Thread mThread;

    // 当前引用的回复
    PrepareQuoteReply mQuoteReply;

    SmileFragment mSmileFragment;

    private OnReplySuccess onReplySuccess;

    public static FastReplyFragment getInstance() {
        return FastReplyFragment_.builder().build();
    }

    public void setPlateAndThread(Plate plate, Thread thread) {
        this.mQuoteReply = null;
        this.mPlate = plate;
        this.mThread = thread;
        SmileyPickerUtility.showKeyBoard(editTextFastReply);
        String hint = "回复: " + thread.getTitle();

        setHint(hint);
    }

    public void setPrepareQuoteReply(PrepareQuoteReply quoteReply) {
        this.mQuoteReply = quoteReply;
        setHint(quoteReply.getQuoteBody());
    }

    void setHint(String hint) {
        SmileyPickerUtility.showKeyBoard(editTextFastReply);
        // editTextFastReply.setHint(Html.fromHtml(hint));
        textViewHint.setText(Html.fromHtml(hint));
    }

    @Override
    protected void onAfterViews() {
        btnReplySend.setOnClickListener(this);
        viewSmile.setOnClickListener(this);

        mSmileFragment = SmileFragment.getInstance();
        getChildFragmentManager().beginTransaction().replace(R.id.layout_smile, mSmileFragment).commit();
        mSmileFragment.setmOnSmileChoose(new OnSmileChoose() {

            @Override
            public void onSmileChoose(Entry<String, String> smile) {
                int currentPosition = editTextFastReply.getSelectionStart();// 得到当前光标位置
                editTextFastReply.getText().insert(currentPosition, smile.getKey());// 插入表情
                setFaceText(editTextFastReply, editTextFastReply.getText().toString());
                editTextFastReply.setSelection(currentPosition + smile.getKey().length());

            }
        });

    }

    private void setFaceText(TextView textView, String text) {
        SpannableString spanStr = parseString(text);
        textView.setText(spanStr);
    }

    private void setFace(SpannableStringBuilder spb, String smileName, int length) {
        String path = SmileTable.get(smileName);
        try {
            int height = (int) editTextFastReply.getTextSize() * 2;
            GifDrawable drawable = new GifDrawable(ChhApplication.getInstance().getAssets(), path);
            // Drawable drawable = Drawable.createFromStream(getResources().getAssets().open(path), smileName);
            drawable.setBounds(0, 0, height, height);
            ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
            SpannableString spanStr = new SpannableString(smileName);
            spanStr.setSpan(imageSpan, 0, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            spb.append(spanStr);
        } catch (IOException e) {
            e.printStackTrace();
            spb.append(smileName);
        }

    }

    private SpannableString parseString(String inputStr) {
        SpannableStringBuilder spb = new SpannableStringBuilder();
        Pattern mPattern = Pattern.compile("\\[{1}.{2}\\]{1}");
        Matcher mMatcher = mPattern.matcher(inputStr);
        String tempStr = inputStr;

        while (mMatcher.find()) {
            int start = mMatcher.start();
            int end = mMatcher.end();
            spb.append(tempStr.substring(0, start));
            String faceName = mMatcher.group();
            setFace(spb, faceName, end - start);
            tempStr = tempStr.substring(end, tempStr.length());
            /**
             * 更新查找的字符串
             */
            mMatcher.reset(tempStr);
        }
        spb.append(tempStr);
        return new SpannableString(spb);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_reply_send:
                if (!ChhApplication.getInstance().isLogin()) {
                    ToastUtil.show(getActivity(), R.string.need_login);
                    startActivity(LoginActivity.getStartIntent(getActivity()));
                    return;
                }
                if (mQuoteReply != null) {
                    quoteReply();
                } else {
                    reply();

                }
            case R.id.button_smile:
                if (layoutSmile.getVisibility() == View.VISIBLE) {
                    SmileyPickerUtility.showKeyBoard(editTextFastReply);
                    layoutSmile.setVisibility(View.GONE);
                } else {
                    int height = SmileyPickerUtility.getKeyboardHeight(getActivity());
                    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) layoutSmile.getLayoutParams();
                    params.height = height;
                    layoutSmile.setVisibility(View.VISIBLE);
                    SmileyPickerUtility.hideSoftInput(editTextFastReply);
                }
                break;
            default:
                break;
        }
    }

    private void quoteReply() {
        String message = editTextFastReply.getText().toString();
        if (TextUtils.isEmpty(message)) {
            Toast.makeText(getActivity(), "不能为空", Toast.LENGTH_SHORT).show();
            return;
        }
        mQuoteReply.setMessage(message);

        ApiHelper.requestApi(ChhApi.quotrReply(mQuoteReply), new ReplyApiCallBack());
    }

    void reply() {
        String message = editTextFastReply.getText().toString();
        if (TextUtils.isEmpty(message)) {
            Toast.makeText(getActivity(), "不能为空", Toast.LENGTH_SHORT).show();
            return;
        }
        ApiHelper.requestApi(ChhApi.reply(mPlate.getFid(), mThread.getTid(), ChhApplication.getInstance().getFormHash(), message)
                , new ReplyApiCallBack());
    }

    public void show() {
        SmileyPickerUtility.showKeyBoard(editTextFastReply);
    }

    public void hide() {
        SmileyPickerUtility.hideSoftInput(editTextFastReply);
        if (layoutSmile.getVisibility() == View.VISIBLE) {
            layoutSmile.setVisibility(View.GONE);
        }
    }

    public OnReplySuccess getOnReplySuccess() {
        return onReplySuccess;
    }

    public void setOnReplySuccess(OnReplySuccess onReplySuccess) {
        this.onReplySuccess = onReplySuccess;
    }

    private class ReplyApiCallBack extends ApiCallBack<ReplyResult> {
        ProgressDialog dialog;

        @Override
        public void onSuccess(ReplyResult result) {
            if (getActivity() != null && result != null) {
                if (result.isSuccess()) {
                    ToastUtil.show(getActivity(), "回复成功");
                    SmileyPickerUtility.hideSoftInput(editTextFastReply);
                    hide();
                    if (onReplySuccess != null) {
                        onReplySuccess.onSuccess(result.getPostListWrap().getPosts());
                    }
                    editTextFastReply.setText("");
                } else {
                    ToastUtil.show(getActivity(), result.getMessage());
                }
            }
        }

        @Override
        public void onStart() {
            dialog = new ProgressDialog(getActivity());
            dialog.setMessage("发送中……");
            dialog.show();
        }

        @Override
        public void onFailure(Throwable error, String content) {
            error.printStackTrace();
            if (getActivity() != null) {
                Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFinish() {
            if (dialog.isShowing()) {
                dialog.cancel();
            }
        }
    }

    public static interface OnReplySuccess {
        void onSuccess(List<Post> posts);
    }
} public static interface OnReplySuccess {
    void onSuccess(List<Post> posts);
} @EFragment(R.layout.fragment_post_list)
public class PostListFragment extends BaseFragment implements AdapterView.OnItemLongClickListener {
    @ViewById(R.id.listView_post)
    ExtendListView mRefreshListView;

    PostListAdapter mPostListAdapter;

    @FragmentArg
    protected int mPage;//回帖页码，从1开始

    @FragmentArg
    protected com.fei_ke.chiphellclient.bean.Thread mThread;

    @InstanceState
    protected ArrayList<Post> mData;

    private boolean mIsFreshing;

    public static PostListFragment getInstance(int page, Thread thread) {
        return PostListFragment_.builder()
                .mPage(page)
                .mThread(thread)
                .build();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPostListAdapter = new PostListAdapter();

    }

    @Override
    protected void onAfterViews() {
        mRefreshListView.setAdapter(mPostListAdapter);
        mRefreshListView.setOnItemLongClickListener(this);
        mRefreshListView.setOnScrollListener(
                new SpeedyQuickReturnListViewOnScrollListener(getActivity(),
                        QuickReturnType.FOOTER, null, getQuickReturnView()));

        mRefreshListView.setOnLastItemVisibleListener(new ExtendListView.OnLastItemVisibleListener() {
            @Override
            public void onLastItemVisible() {
                //                showReplyPanel();
            }
        });

        if (mData == null)
            getPostList(mPage);
    }


    private void showReplyPanel() {
        Activity activity = getActivity();
        if (activity instanceof ThreadDetailActivity) {
            ((ThreadDetailActivity) activity).showReplyPanel();
        }
    }

    private void hideReplyPanel() {
        Activity activity = getActivity();
        if (activity instanceof ThreadDetailActivity) {
            ((ThreadDetailActivity) activity).hideReplyPanel();
        }
    }


    private View getQuickReturnView() {
        Activity activity = getActivity();
        if (activity instanceof ThreadDetailActivity) {
            return ((ThreadDetailActivity) activity).getReplyPanel();
        }
        return null;
    }

    private void onEndRefresh() {
        Activity activity = getActivity();
        if (activity instanceof ThreadDetailActivity) {
            ((ThreadDetailActivity) activity).postEndRefresh();
        }
    }

    private void onStartRefresh() {
        Activity activity = getActivity();
        if (activity instanceof ThreadDetailActivity) {
            ((ThreadDetailActivity) activity).postStartRefresh();
        }
    }

    private void setPrepareQuoteReply(PrepareQuoteReply quoteReply) {
        Activity activity = getActivity();
        if (activity instanceof ThreadDetailActivity) {
            ((ThreadDetailActivity) activity).setPrepareQuoteReply(quoteReply);
        }
    }

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        // TODO 第一条为主贴，无法引用
        if (mPage == 1 && id == 0) {
            //            mFastReplyFragment.setPlateAndThread(mPlate, mThread);
            return true;
        }

        Post post = mPostListAdapter.getItem((int) id);

        String url = post.getReplyUrl();
        if (TextUtils.isEmpty(url)) {
            Toast.makeText(getActivity(), R.string.not_login, Toast.LENGTH_SHORT).show();
            return true;
        }
        ApiHelper.requestApi(ChhApi.prepareQuoteReply(post.getReplyUrl()), new ApiCallBack<PrepareQuoteReply>() {
            ProgressDialog dialog;

            @Override
            public void onStart() {
                dialog = new ProgressDialog(getActivity());
                dialog.setMessage("正在准备……");
                dialog.setCanceledOnTouchOutside(false);
                dialog.show();
            }

            @Override
            public void onSuccess(PrepareQuoteReply result) {
                setPrepareQuoteReply(result);
                if (dialog.isShowing()) {
                    showReplyPanel();
                }
            }

            @Override
            public void onFailure(Throwable error, String content) {
                error.printStackTrace();
                ToastUtil.show(getActivity(), "oops 获取失败了");
            }

            @Override
            public void onFinish() {
                if (dialog.isShowing()) {
                    dialog.dismiss();
                }
            }

        });
        return true;
    }

    public void update(List<Post> posts) {
        if (mPage == 1) {
            posts.remove(0);
        }
        mPostListAdapter.update(posts);
        mRefreshListView.setSelection(mPostListAdapter.getCount() - 1);
    }

    public void update() {
        getPostList(mPage);
    }

    private void getPostList(final int page) {
        if (mIsFreshing) {
            return;
        }
        mIsFreshing = true;
        if (mPage < 1) {
            mPage = 1;
        }
        ApiHelper.requestApi(ChhApi.getPostList(mThread, page), new ApiCallBack<PostListWrap>() {
            @Override
            public void onStart() {
                onStartRefresh();
            }

            @Override
            public void onCache(PostListWrap result) {
                if (result == null || result.size() == 0 || mData != null) {
                    return;
                }

                //                if (page == 1) {
                //                    loadMainContent(result.get(0));
                //                    mPostListAdapter.clear();
                //                }
                List<Post> posts = result.getPosts();
                if (mPage == 1) {
                    posts.get(0).setContent("");
                }
                mPostListAdapter.update(posts);
            }

            @Override
            public void onSuccess(PostListWrap result) {
                if (result == null || result.size() == 0) {
                    return;
                }

                //                if (page == 1) {
                //                    loadMainContent(result.get(0));
                //                    mPostListAdapter.clear();
                //
                //                    // 将该帖子设为已读
                //                    new ThreadStatusUtil(getApplicationContext()).setRead(mThread.getTid());
                //                }
                mData = (ArrayList<Post>) result.getPosts();
                if (mPage == 1) {
                    mData.get(0).setContent("");
                    mData.get(0).setImgList(null);
                }
                boolean hasNewData = mPostListAdapter.update(mData);
                if (!hasNewData) {
                    // mPage -= 1;
                    // TODO页码处理
                }
            }

            @Override
            public void onFailure(Throwable error, String content) {
                ToastUtil.show(getActivity(), "oops 刷新失败了");
            }

            @Override
            public void onFinish() {
                mIsFreshing = false;
                onEndRefresh();
            }

        });

    }


    public boolean isListOnTop() {
        if (null == mPostListAdapter || mPostListAdapter.isEmpty()) {
            return true;

        } else {
            /**
             * This check should really just be:
             * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
             * internally use a HeaderView which messes the positions up. For
             * now we'll just add one to account for it and rely on the inner
             * condition which checks getTop().
             */
            if (mRefreshListView.getFirstVisiblePosition() == 0) {
                final View firstVisibleChild = mRefreshListView.getChildAt(0);
                if (firstVisibleChild != null) {
                    return firstVisibleChild.getTop() >= mRefreshListView.getTop();
                }
            }
        }

        return false;
    }

} public class ThreadStatusUtil {
    private static final String READ_STATUS = "READ_STATUS";
    private SharedPreferences preferences;

    public ThreadStatusUtil(Context context) {
        preferences = context.getSharedPreferences(READ_STATUS, Context.MODE_PRIVATE);
    }

    /**
     * 获取帖子状态
     *
     * @param tid
     * @return
     */
    public synchronized boolean isRead(String tid) {
        return preferences.getBoolean(tid, false);
    }

    /**
     * 设置帖子状态
     *
     * @param tid
     * @param read
     */
    public synchronized void setRead(String tid, boolean read) {
        preferences.edit().putBoolean(tid, read).commit();
    }

    /**
     * 将帖子标记为已读状态
     *
     * @param tid
     */
    public synchronized void setRead(String tid) {
        setRead(tid, true);
    }

} public class ToastUtil {
    public static void show(Context context, CharSequence text) {
        if (context != null) {
            Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
        }
    }

    public static void show(Context context, int stringResId) {
        if (context != null) {
            Toast.makeText(context, stringResId, Toast.LENGTH_SHORT).show();
        }
    }
}
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import com.fei_ke.chiphellclient.ChhApplication;
import com.fei_ke.chiphellclient.R;
import com.fei_ke.chiphellclient.api.ChhApi;
import com.fei_ke.chiphellclient.api.support.ApiCallBack;
import com.fei_ke.chiphellclient.api.support.ApiHelper;
import com.fei_ke.chiphellclient.bean.Plate;
import com.fei_ke.chiphellclient.bean.Post;
import com.fei_ke.chiphellclient.bean.PostListWrap;
import com.fei_ke.chiphellclient.bean.PrepareQuoteReply;
import com.fei_ke.chiphellclient.bean.Thread;
import com.fei_ke.chiphellclient.constant.Constants;
import com.fei_ke.chiphellclient.ui.adapter.PostPageAdapter;
import com.fei_ke.chiphellclient.ui.customviews.MySlidingUpPanelLayout;
import com.fei_ke.chiphellclient.ui.fragment.FastReplyFragment;
import com.fei_ke.chiphellclient.ui.fragment.FastReplyFragment.OnReplySuccess;
import com.fei_ke.chiphellclient.ui.fragment.PostListFragment;
import com.fei_ke.chiphellclient.utils.ThreadStatusUtil;
import com.fei_ke.chiphellclient.utils.ToastUtil;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.Extra;
import org.androidannotations.annotations.FragmentByTag;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ViewById;
import java.util.ArrayList;
import java.util.List;
package com.fei_ke.chiphellclient.ui.activity;





/**
 * 帖子内容
 *
 * @author fei-ke
 * @2014-6-15
 */
@EActivity(R.layout.activity_thread_detail)
public class ThreadDetailActivity extends BaseActivity {

    private static final String TAG = "ThreadDetailActivity";
    @ViewById
    ViewPager viewPagerPost;

    @ViewById
    ViewGroup layoutSlideUp;

    @Extra
    Plate mPlate;

    @Extra
    @InstanceState
    Thread mThread;

    @FragmentByTag("fast_reply")
    FastReplyFragment mFastReplyFragment;

    // @ViewById(R.id.main_post)
    // PostMainView mMainPostView;
    @ViewById(R.id.webView_content)
    WebView webViewContent;

    @ViewById(R.id.layout_fast_reply)
    View mlayoutFastReply;

    @ViewById(R.id.sliding_layout)
    MySlidingUpPanelLayout mPanelLayout;

    @ViewById(R.id.refreshLayout)
    SwipeRefreshLayout mRefreshLayout;

    @ViewById
    TextView textViewTotalPage;

    @ViewById
    Spinner spinnerPage;
    @ViewById(R.id.dragView)
    View dragView;
    PostPageAdapter mPostPageAdapter;
    private boolean mIsFreshing;

    private List<String> images = new ArrayList<>();

    public static Intent getStartIntent(Context context, Plate plate, Thread thread) {
        return ThreadDetailActivity_.intent(context).mThread(thread).mPlate(plate).get();
    }

    @Override
    protected void onAfterViews() {
        if (mThread == null) {
            handExportUrl();
        }

        mFastReplyFragment.setPlateAndThread(mPlate, mThread);


        setTitle(mPlate.getTitle());
        setSubtitle(mThread.getTitle());
        mPostPageAdapter = new PostPageAdapter(getSupportFragmentManager(), mThread);
        viewPagerPost.setAdapter(mPostPageAdapter);

        mRefreshLayout.setColorSchemeColors(getResources().getIntArray(R.array.gplus_colors));
        mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                getPostList();
            }
        });

        spinnerPage.setTag(0);
        spinnerPage.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if ((Integer) spinnerPage.getTag() == position) return;

                viewPagerPost.setCurrentItem(position, false);
                if (!mPanelLayout.isPanelExpanded()) {
                    mPanelLayout.expandPanel();
                }

                spinnerPage.setTag(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
        viewPagerPost.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i2) {

            }

            @Override
            public void onPageSelected(int i) {
                spinnerPage.setSelection(i);
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });
        mFastReplyFragment.setOnReplySuccess(new OnReplySuccess() {