content: package com.github.airsaid.accountbook.mvp.count;
  
  import android.content.Intent;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import android.graphics.Color;
  import android.graphics.Typeface;
  import android.os.Bundle;
  import android.os.Message;
  import android.support.annotation.Nullable;
  import android.support.v4.widget.SwipeRefreshLayout;
  import android.support.v7.widget.LinearLayoutManager;
  import android.support.v7.widget.RecyclerView;
  import android.text.SpannableString;
  import android.text.TextUtils;
  import android.text.style.ForegroundColorSpan;
  import android.text.style.RelativeSizeSpan;
  import android.text.style.StyleSpan;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.ImageButton;
  import android.widget.TextView;
  
  import com.chad.library.adapter.base.BaseQuickAdapter;
  import com.github.airsaid.accountbook.R;
  import com.github.airsaid.accountbook.adapter.CountListAdapter;
  import com.github.airsaid.accountbook.base.BaseApplication;
  import com.github.airsaid.accountbook.base.BaseFragment;
  import com.github.airsaid.accountbook.constants.AppConfig;
  import com.github.airsaid.accountbook.constants.AppConstants;
  import com.github.airsaid.accountbook.constants.MsgConstants;
  import com.github.airsaid.accountbook.data.Account;
  import com.github.airsaid.accountbook.data.CountList;
  import com.github.airsaid.accountbook.data.Error;
  import com.github.airsaid.accountbook.data.Type;
  import com.github.airsaid.accountbook.data.TypeDao;
  import com.github.airsaid.accountbook.util.ArithUtils;
  import com.github.airsaid.accountbook.util.ChartUtils;
  import com.github.airsaid.accountbook.util.DateUtils;
  import com.github.airsaid.accountbook.util.PaletteUtils;
  import com.github.airsaid.accountbook.util.ToastUtils;
  import com.github.airsaid.accountbook.util.UiUtils;
  import com.github.airsaid.accountbook.util.UserUtils;
  import com.github.airsaid.accountbook.widget.ChartFormatter;
  import com.github.airsaid.accountbook.widget.recycler.HorizontalDividerItemDecoration;
  import com.github.airsaid.accountbook.widget.recycler.OnSimpleClickListener;
  import com.github.mikephil.charting.charts.PieChart;
  import com.github.mikephil.charting.data.Entry;
  import com.github.mikephil.charting.data.PieData;
  import com.github.mikephil.charting.data.PieDataSet;
  import com.github.mikephil.charting.data.PieEntry;
  import com.github.mikephil.charting.highlight.Highlight;
  import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
  
  import org.greenrobot.eventbus.EventBus;
  import org.greenrobot.eventbus.Subscribe;
  import org.greenrobot.eventbus.ThreadMode;
  
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  
  import butterknife.BindView;
  import butterknife.OnClick;
  
  /**
   * @author Airsaid
   * @github https://github.com/airsaid
   * @date 2017/5/12
   * @desc 统计 Fragment
   */
  public class CountFragment extends BaseFragment implements CountContract.View
          , SwipeRefreshLayout.OnRefreshListener, ChartFormatter.OnFormattedFinishListener {
  
      /** 统计当前用户所有账目 */
      public static final int QUERY_TYPE_ALL_ME = 1;
      /** 统计当前用户的当前帐薄中所有账目 */
      public static final int QUERY_TYPE_BOOK_ALL = 2;
      /** 统计当前用户的当前帐薄中当前用户所有账目 */
      public static final int QUERY_TYPE_BOOK_ME = 3;
  
      @BindView(R.id.ibt_left)
      ImageButton mIbtLeft;
      @BindView(R.id.txt_month)
      TextView mTxtMonth;
      @BindView(R.id.ibt_right)
      ImageButton mIbtRight;
      @BindView(R.id.refreshLayout)
      SwipeRefreshLayout mRefreshLayout;
      @BindView(R.id.recyclerView)
      RecyclerView mRecyclerView;
      @BindView(R.id.pieChartView)
      PieChart mChartView;
  
      private CountListAdapter mAdapter;
      private CountContract.Presenter mPresenter;
  
      // 分类对应总金额集合
      private HashMap<String, Double> mMoneyMap = new HashMap<>();
      // 分类对应图标集合
      private HashMap<String, String> mIconMap = new HashMap<>();
      // 分类对应百分比集合
      private HashMap<String, Float> mPercentMap = new HashMap<>();
      // 分类对应颜色值
      private HashMap<String, Integer> mColorMap = new HashMap<>();
      // 记账类型数据
      private List<Type> mTypes;
      // 统计类型（支出/收入），默认支出
      private int mCountType = AppConfig.TYPE_COST;
      // 查询类型，默认查询当前用户所有账目
      private int mQueryType = QUERY_TYPE_ALL_ME;
  
      private String mStartDate;
      private String mEndDate;
  
      @Override
      public void setPresenter(CountContract.Presenter presenter) {
          this.mPresenter = presenter;
      }
  
      public static CountFragment newInstance(Bundle args) {
          CountFragment fragment = new CountFragment();
          fragment.setArguments(args);
          return fragment;
      }
  
      @Override
      public View getLayout(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
          return inflater.inflate(R.layout.fragment_count, null);
      }
  
      @Override
      public void onCreateFragment(@Nullable Bundle savedInstanceState) {
          mRefreshLayout.setColorSchemeResources(
                  UiUtils.getResourceId(mContext, R.attr.colorAccent, R.color.colorAccent));
          mRefreshLayout.setOnRefreshListener(this);
          initTypeData();
          initAdapter();
          initChart();
          initData();
      }
  
      @Override
      public void onStart() {
          if (!EventBus.getDefault().isRegistered(this)) {
              EventBus.getDefault().register(this);
          }
          super.onStart();
      }
  
      /**
       * 初始化分类数据
       */
      private void initTypeData() {
          Bundle bundle = getArguments();
          if (bundle != null) {
              mCountType = bundle.getInt(AppConstants.EXTRA_TYPE, AppConfig.TYPE_COST);
          }
  
          TypeDao dao = BaseApplication.getInstance().getSession().getTypeDao();
          mTypes = new ArrayList<>();
          if (mCountType == AppConfig.TYPE_COST) {
              mTypes = dao.queryBuilder()
                      .where(TypeDao.Properties.Uid.eq(UserUtils.getUid()), TypeDao.Properties.Type.eq(AppConfig.TYPE_COST))
                      .orderAsc(TypeDao.Properties.Index)
                      .list();
          } else {
              mTypes = dao.queryBuilder()
                      .where(TypeDao.Properties.Uid.eq(UserUtils.getUid()), TypeDao.Properties.Type.eq(AppConfig.TYPE_INCOME))
                      .orderAsc(TypeDao.Properties.Index)
                      .list();
          }
      }
  
      /**
       * 初始化适配器
       */
      private void initAdapter() {
          mRecyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(mContext)
                  .color(R.color.colorDivide)
                  .size(2)
                  .build());
          mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
          mAdapter = new CountListAdapter(R.layout.item_count_list, new ArrayList<CountList>());
          mAdapter.setEmptyView(UiUtils.getEmptyView(mContext, mRecyclerView
                  , UiUtils.getString(R.string.empty_count_data), R.mipmap.ic_pie_empty));
          mRecyclerView.setAdapter(mAdapter);
          mRecyclerView.addOnItemTouchListener(new OnSimpleClickListener(){
              @Override
              public void onItemClick(BaseQuickAdapter baseQuickAdapter, View view, int i) {
                  CountList count = (CountList) baseQuickAdapter.getData().get(i);
                  startActivity(new Intent(mContext, TypeCountDetailActivity.class)
                          .putExtra(AppConstants.EXTRA_TYPE_NAME, count.getTypeName())
                          .putExtra(AppConstants.EXTRA_TYPE, mCountType)
                          .putExtra(AppConstants.EXTRA_START_DATE, mStartDate)
                          .putExtra(AppConstants.EXTRA_END_DATE, mEndDate));
              }
          });
      }
  
      /**
       * 初始化图表
       */
      private void initChart() {
          ChartUtils.initPieChart(mChartView);
          mChartView.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
              @Override
              public void onValueSelected(Entry e, Highlight h) {
                  // 单独显示每个分类的统计情况
                  PieEntry entry = (PieEntry) e;
                  float money = entry.getValue();
                  String type = entry.getLabel();
                  mChartView.setCenterText(generateCenterSpannableText(
                          String.valueOf(money), "(".concat(type).concat(")")));
              }
  
              @Override
              public void onNothingSelected() {
                  setChartData();
              }
          });
      }
  
      /**
       * 初始化数据，默认为系统时间当前月
       */
      private void initData() {
          mStartDate = DateUtils.getCurrentDate(DateUtils.FORMAT_MAIN_TAB);
          mEndDate = DateUtils.getDateNxtMonth(mStartDate, DateUtils.FORMAT_MAIN_TAB, 1);
          onRefresh();
      }
  
      @Override
      public void onRefresh() {
          if(mRefreshLayout == null) return;
  
          mRefreshLayout.post(new Runnable() {
              @Override
              public void run() {
                  clearData();
                  mRefreshLayout.setRefreshing(true);
                  queryAccounts(mStartDate, mEndDate, mQueryType, mCountType);
              }
          });
      }
  
      /**
       * 清空数据
       */
      private void clearData() {
          mMoneyMap.clear();
          mIconMap.clear();
          mPercentMap.clear();
          mColorMap.clear();
          setChartData();
          setCountListData();
      }
  
      @Override
      public void queryAccounts(String startDate, String endDate, int queryType, int type) {
          SimpleDateFormat f = new SimpleDateFormat(DateUtils.FORMAT_MAIN_TAB, Locale.CHINA);
          try {
              Date date = f.parse(startDate);
              String text = f.format(date);
              mTxtMonth.setText(text);
          } catch (ParseException e) {
              e.printStackTrace();
          }
          mPresenter.queryAccounts(UserUtils.getUser(), mStartDate, mEndDate, queryType, type);
      }
  
      @Override
      public void queryAccountsSuccess(List<Account> accounts) {
          mRefreshLayout.setRefreshing(false);
          mMoneyMap.clear();
          mIconMap.clear();
          mColorMap.clear();
          if (accounts != null && accounts.size() > 0) {
              for (Account account : accounts) {
                  String type = account.getCType();
                  String icon = account.getTypeIcon();
                  double money = Double.parseDouble(account.getMoney());
  
                  // 判断 typeIcon 字段是否为空
                  if (!TextUtils.isEmpty(icon)) {
                      // 保存图片名称
                      mIconMap.put(type, icon);
                  } else {
                      // 兼容旧版本
                      for (Type costType : mTypes) {
                          if (costType.getName().equals(type)) {
                              mIconMap.put(type, costType.getIcon());
                              break;
                          }
                      }
                  }
  
                  // 如果已经存在该分类，累加金额
                  if (mMoneyMap.containsKey(type)) {
                      double resultMoney = ArithUtils.add(mMoneyMap.get(type), money);
                      mMoneyMap.put(type, resultMoney);
                  } else {
                      mMoneyMap.put(type, money);
                  }
              }
          }
  
          setChartData();
      }
  
      @Override
      public void queryAccountsFail(Error e) {
          ToastUtils.show(mContext, e.getMessage());
          mRefreshLayout.setRefreshing(false);
      }
  
      /**
       * 设置图表数据
       */
      @Override
      public void setChartData() {
          if (mMoneyMap.size() > 0) {
              mChartView.setVisibility(View.VISIBLE);
              // 设置总支出/收入
              String typeStr = mCountType == AppConfig.TYPE_COST
                      ? UiUtils.getString(R.string.total_cost_chart)
                      : UiUtils.getString(R.string.total_income_chart);
              mChartView.setCenterText(generateCenterSpannableText(
                      String.valueOf(getTotalMoney()), typeStr));
              // 设置图表数据与颜色
              ArrayList<PieEntry> entries = new ArrayList<>();
              ArrayList<Integer> colors = new ArrayList<>();
              for (Map.Entry<String, Double> entry : mMoneyMap.entrySet()) {
                  // 添加分类、金额数据
                  Float money = Float.valueOf(String.valueOf(entry.getValue()));
                  String type = entry.getKey();
                  PieEntry pieEntry = new PieEntry(money, type);
                  entries.add(pieEntry);
                  // 添加从分类图片中取色的颜色
                  String iconName = mIconMap.get(entry.getKey());
                  Bitmap bitmap = BitmapFactory.decodeResource(getResources(), UiUtils.getImageResIdByName(iconName));
                  int colorRgb = PaletteUtils.getColorRgb(bitmap);
                  mColorMap.put(type,colorRgb);
                  colors.add(colorRgb);
              }
  
              PieDataSet dataSet = new PieDataSet(entries, "");
              dataSet.setSliceSpace(3f);
              dataSet.setSelectionShift(5f);
              dataSet.setColors(colors);
  
              PieData data = new PieData(dataSet);
              ChartFormatter formatter = new ChartFormatter(mPercentMap, mMoneyMap.size());
              formatter.setOnFormattedValueListener(this);
              data.setValueFormatter(formatter);
              data.setValueTextSize(11f);
              data.setValueTextColor(Color.WHITE);
              mChartView.setData(data);
              mChartView.animateX(800);
          }else{
              mChartView.setVisibility(View.GONE);
          }
      }
  
      /**
       * 生成图标中心文字的 SpannableString
       *
       * @return SpannableString
       */
      private SpannableString generateCenterSpannableText(String money, String descText) {
          SpannableString s = new SpannableString(UiUtils.getString(R.string.rmb)
                  .concat(money).concat("\n").concat(descText));
          s.setSpan(new RelativeSizeSpan(1.7f), 0, s.length() - descText.length(), 0);
          s.setSpan(new StyleSpan(Typeface.BOLD), 0, s.length() - descText.length(), 0);
          s.setSpan(new ForegroundColorSpan(UiUtils.getColor(R.color.textRed))
                  , 0, s.length() - descText.length(), 0);
          s.setSpan(new RelativeSizeSpan(.9f), s.length() - descText.length(), s.length(), 0);
          s.setSpan(new StyleSpan(Typeface.ITALIC), s.length() - descText.length(), s.length(), 0);
          s.setSpan(new ForegroundColorSpan(UiUtils.getColor(R.color.textGrayish))
                  , s.length() - descText.length(), s.length(), 0);
          return s;
      }
  
      @Override
      public void onFormattedValue(HashMap<String, Float> percentMap) {
          setCountListData();
      }
  
      /**
       * 设置统计列表数据
       */
      private void setCountListData() {
          List<CountList> list = new ArrayList<>();
          for (Map.Entry<String, Double> entry : mMoneyMap.entrySet()) {
              String type = entry.getKey();
              Double money = entry.getValue();
              String icon = mIconMap.get(type);
              Float percent = mPercentMap.get(type);
              Integer color = mColorMap.get(type);
  
              CountList count = new CountList();
              count.setTypeName(type)
                      .setTotalMoney(money)
                      .setIconName(icon)
                      .setColor(color)
                      .setPercent(percent);
  
              list.add(count);
          }
          mAdapter.setNewData(sortCountList(list));
      }
  
      /**
       * 对统计列表按照金额大小进行倒序排序
       *
       * @param list 统计列表数据
       * @return 排序后的统计列表数据
       */
      private List<CountList> sortCountList(List<CountList> list) {
          if (list.size() > 0) {
              Collections.sort(list, new Comparator<CountList>() {
                  @Override
                  public int compare(CountList t2, CountList t1) {
                      double money1 = t1.getTotalMoney();
                      double money2 = t2.getTotalMoney();
                      if (money1 > money2) {
                          return 1;
                      } else if (money1 == money2) {
                          return 0;
                      }
                      return -1;
                  }
              });
          }
          return list;
      }
  
      @Override
      public double getTotalMoney() {
          Double totalMoney = 0.0;
          for (Map.Entry<String, Double> entry : mMoneyMap.entrySet()) {
              totalMoney = ArithUtils.add(totalMoney, entry.getValue());
          }
          return totalMoney;
      }
  
      @Override
      public void setQueryType(int type) {
          mQueryType = type;
          if(isVisible())
              onRefresh();
      }
  
      @OnClick({R.id.ibt_left, R.id.ibt_right})
      public void onClick(View view) {
          switch (view.getId()) {
              case R.id.ibt_left: // 请求上月数据
                  mStartDate = DateUtils.getDateNxtMonth(mStartDate, DateUtils.FORMAT_MAIN_TAB, -1);
                  mEndDate = DateUtils.getDateNxtMonth(mStartDate, DateUtils.FORMAT_MAIN_TAB, 1);
                  onRefresh();
                  break;
              case R.id.ibt_right:// 请求下月数据
                  mStartDate = mEndDate;
                  mEndDate = DateUtils.getDateNxtMonth(mStartDate, DateUtils.FORMAT_MAIN_TAB, 1);
                  onRefresh();
                  break;
          }
      }
  
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void onMessageEvent(Message msg) {
          switch (msg.what) {
              case MsgConstants.MSG_SAVE_ACCOUNT_SUCCESS:
                  onRefresh();
                  break;
          }
      }
  
      @Override
      public void onDestroy() {
          if (EventBus.getDefault().isRegistered(this)) {
              EventBus.getDefault().unregister(this);
          }
          super.onDestroy();
      }
  }
  