/FileExtraction/Java_unseen/Kegbot_kegbot-android/kegtab/src/main/java/org/kegbot/app/PourStatusFragment.java
/*
 * Copyright 2003-2020 The Kegbot Project contributors <info@kegbot.org>
 *
 * This file is part of the Kegtab package from the Kegbot project. For
 * more information on Kegtab or Kegbot, see <http://kegbot.org/>.
 *
 * Kegtab is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 2.
 *
 * Kegtab is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with Kegtab. If not, see <http://www.gnu.org/licenses/>.
 */
package org.kegbot.app;

import android.app.Activity;
import android.app.ListFragment;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.squareup.otto.Subscribe;

import org.kegbot.app.event.FlowUpdateEvent;
import org.kegbot.app.util.ImageDownloader;
import org.kegbot.app.util.Units;
import org.kegbot.app.view.BadgeView;
import org.kegbot.core.AuthenticationManager;
import org.kegbot.core.Flow;
import org.kegbot.core.KegbotCore;
import org.kegbot.proto.Models.Keg;
import org.kegbot.proto.Models.KegTap;

import java.util.concurrent.TimeUnit;

public class PourStatusFragment extends ListFragment {

  private static final String TAG = PourStatusFragment.class.getSimpleName();

  private static final double VOLUME_COUNTER_INCREMENT_ML = 10;
  private static final long VOLUME_COUNTER_INCREMENT_DELAY_MILLIS = 20;

  private static final String ARG_TAP_ID = "tap_id";

  private static final int AUTH_DRINKER_REQUEST = 1;
  /**
   * After this much inactivity, the "pour automatically ends" dialog is shown.
   */
  private static final long IDLE_TOOLTIP_MILLIS = TimeUnit.SECONDS.toMillis(5);
  private final Handler mHandler = new Handler(Looper.getMainLooper());
  private double mTargetVolumeMl = 0.0;
  private double mCurrentVolumeMl = 0.0;
  private KegbotCore mCore;
  private ImageDownloader mImageDownloader;

  private View mView;
  private BadgeView mPourVolumeBadge;
  private TextView mTapTitle;
  private TextView mTapSubtitle;
  private TextView mStatusLine;
  private ImageView mBeerImage;

  private final Runnable mCounterIncrementRunnable = new Runnable() {
    @Override
    public void run() {
      final double remain = mTargetVolumeMl - mCurrentVolumeMl;
      if (remain <= 0) {
        return;
      }

      mCurrentVolumeMl += Math.min(remain, VOLUME_COUNTER_INCREMENT_ML);
      setVolumeDisplay(mCurrentVolumeMl);

      if (mCurrentVolumeMl < mTargetVolumeMl) {
        mHandler.postDelayed(mCounterIncrementRunnable, VOLUME_COUNTER_INCREMENT_DELAY_MILLIS);
      }
    }
  };
  private Flow mFlow = null;
  private final Runnable mCountdownRunnable = new Runnable() {
    @Override
    public void run() {
      final Flow flow = mFlow;
      if (flow != null) {
        if (flow.isFinished()) {
          mStatusLine.setVisibility(View.VISIBLE);
          mStatusLine.setText(getString(R.string.pour_status_complete));
        } else {
          if (mFlow.getIdleTimeMs() >= IDLE_TOOLTIP_MILLIS) {
            final long seconds = mFlow.getMsUntilIdle() / 1000;
            mStatusLine.setText("Pour automatically ends in " + seconds + " second"
                + ((seconds != 1) ? "s" : "") + ".");
            mStatusLine.setVisibility(View.VISIBLE);
          } else {
            mStatusLine.setVisibility(View.INVISIBLE);
          }
        }
      }
      mHandler.postDelayed(mCountdownRunnable, 1000);
    }
  };

  public static PourStatusFragment forTap(KegTap tap) {
    final PourStatusFragment frag = new PourStatusFragment();
    final Bundle args = new Bundle();
    args.putInt(ARG_TAP_ID, tap.getId());
    frag.setArguments(args);
    return frag;
  }

  private KegTap getTap() {
    return mCore.getTapManager().getTap(getArguments().getInt(ARG_TAP_ID));
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mCore = KegbotCore.getInstance(getActivity());
    mImageDownloader = mCore.getImageDownloader();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mView = inflater.inflate(R.layout.pour_status_item_layout, container, false);

    mPourVolumeBadge = (BadgeView) mView.findViewById(R.id.tapStatsBadge1);
    mPourVolumeBadge.setBadgeValue("0.0");
    mPourVolumeBadge.setBadgeCaption("Ounces Poured");

    mTapTitle = (TextView) mView.findViewById(R.id.tapTitle);
    mTapSubtitle = (TextView) mView.findViewById(R.id.tapSubtitle);

    mStatusLine = (TextView) mView.findViewById(R.id.tapNotes);
    mBeerImage = (ImageView) mView.findViewById(R.id.tapImage);

    setVolumeDisplay(0);

    return mView;
  }

  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
      case AUTH_DRINKER_REQUEST:
        if (resultCode == Activity.RESULT_OK) {
          final String username =
              data.getStringExtra(KegtabCommon.ACTIVITY_AUTH_DRINKER_RESULT_EXTRA_USERNAME);
          if (!Strings.isNullOrEmpty(username)) {
            Log.d(TAG, "Authenticating async.");
            AuthenticationManager am = mCore.getAuthenticationManager();
            am.authenticateUsernameAsync(username);
          }
        }
        break;
      default:
        super.onActivityResult(requestCode, resultCode, data);
    }
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
  }

  @Override
  public void onResume() {
    super.onResume();
    applyTapDetail();
    KegbotCore.getInstance(getActivity()).getBus().register(this);

    startCountdown();
    if (mFlow != null) {
      updateWithFlow(mFlow);
    }
  }

  @Override
  public void onPause() {
    KegbotCore.getInstance(getActivity()).getBus().unregister(this);
    cancelCountdown();
    super.onPause();
  }

  @Subscribe
  public void onFlowUpdate(FlowUpdateEvent event) {
    final Flow flow = event.getFlow();
    final KegTap tap = getTap();
    if (tap != null && tap.getId() == flow.getTap().getId()) {
      if (!flow.isFinished()) {
        updateWithFlow(flow);
      }
    }
  }

  private void setVolumeDisplay(double volumeMl) {
    final Pair<String, String> qty = Units.localizeWithoutScaling(
        mCore.getConfiguration(), volumeMl);
    mPourVolumeBadge.setBadgeValue(qty.first);
    mPourVolumeBadge.setBadgeCaption(Units.capitalizeUnits(qty.second) + " Poured");
  }

  private void applyTapDetail() {
    final KegTap tap = getTap();
    mBeerImage.setImageResource(R.drawable.kegbot_unknown_square_2);

    final Keg keg = tap.getCurrentKeg();

    if (keg != null) {
      final String beerName = keg.getBeverage().getName();

      // Set beer name.
      if (!Strings.isNullOrEmpty(beerName) && mTapTitle != null) {
        mTapTitle.setText(beerName);
      }

      // Set beer image.
      if (keg.getBeverage().hasPicture()) {
        mImageDownloader.download(keg.getBeverage().getPicture().getUrl(), mBeerImage);
      }
      mTapSubtitle.setText(tap.getName());
    } else {
      mTapTitle.setText(tap.getName());
    }
  }

  public void updateWithFlow(final Flow flow) {
    Preconditions.checkNotNull(flow, "null flow given to updateWithFlow()");
    mFlow = flow;

    if (mFlow.isFinished()) {
      return;
    }

    if (mView == null) {
      return;
    }

    // Set volume portion.
    mTargetVolumeMl = flow.getVolumeMl();
    if (mCurrentVolumeMl < mTargetVolumeMl) {
      mHandler.removeCallbacks(mCounterIncrementRunnable);
      mHandler.post(mCounterIncrementRunnable);
    }
  }

  private void cancelCountdown() {
    mHandler.removeCallbacks(mCountdownRunnable);
  }

  private void startCountdown() {
    cancelCountdown();
    mHandler.post(mCountdownRunnable);
  }

}
