/*
 * Copyright (C) 2009 University of Washington
 *
 * 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 org.odk.collect.android.widgets;

import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.support.v7.widget.AppCompatEditText;
import android.text.format.DateUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.CalendarView;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TableLayout;

import org.javarosa.core.model.data.DateData;
import org.javarosa.core.model.data.IAnswerData;
import org.javarosa.form.api.FormEntryPrompt;
import org.joda.time.DateTime;
import org.odk.collect.android.R;

import java.util.Calendar;
import java.util.Date;

/**
 * Displays a DatePicker widget. DateWidget handles leap years and does not allow dates that do not exist.
 *
 * @author Carl Hartung (carlhartung@gmail.com)
 * @author Yaw Anokwa (yanokwa@gmail.com)
 */
public class DateWidget extends QuestionWidget {

  private static final int DATE_UNSET = -1;
  private EditText datePickerEditText;
  private long date;


  @SuppressLint("NewApi")
  public DateWidget(Context context, FormEntryPrompt prompt) {
    super(context, prompt);

    date = DATE_UNSET;

    datePickerEditText = new AppCompatEditText(context);
    datePickerEditText.setId(QuestionWidget.newUniqueId());
    final boolean readOnly = prompt.isReadOnly();
    datePickerEditText.setFocusable(!readOnly);
    datePickerEditText.setEnabled(!readOnly);
    datePickerEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.answer_text));
    if (readOnly) {
      datePickerEditText.setBackgroundDrawable(null);
      datePickerEditText.setFocusable(false);
      datePickerEditText.setClickable(false);
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        datePickerEditText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
      }
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
      datePickerEditText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
    }

    TableLayout.LayoutParams params = new TableLayout.LayoutParams();

    params.setMargins(getResources().getDimensionPixelSize(R.dimen.edittext_padding_start), 0, 0, 0);
    datePickerEditText.setPadding(datePickerEditText.getPaddingLeft(), -1, datePickerEditText.getPaddingRight(),
        datePickerEditText.getPaddingBottom());
    datePickerEditText.setLayoutParams(params);
    datePickerEditText.setSingleLine(true);

    datePickerEditText.setOnTouchListener(new View.OnTouchListener() {

      @Override
      public boolean onTouch(final View v, final MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
          showDatePickerDialog();
          return true;
        }
        return false;
      }

    });

    setGravity(Gravity.START);
    addView(datePickerEditText);

    // If there's an answer, use it.
    setAnswer();
  }

  private void setAnswer() {

    if (mPrompt.getAnswerValue() != null) {
      DateTime ldt = new DateTime(((Date) mPrompt.getAnswerValue().getValue()).getTime());
      final long time = ldt.toDate().getTime();
      date = time;
      formatDate(time);
    } else {
      // create date widget with current time as of right now
      clearAnswer();
    }
  }

  private void formatDate(final long date) {
    final int flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
    final String formattedDate = DateUtils.formatDateTime(getContext(), date, flags);
    datePickerEditText.setText(formattedDate);
  }


  /**
   * Resets date to today.
   */
  @Override
  public void clearAnswer() {
    date = DATE_UNSET;
    datePickerEditText.setText("");
  }


  @Override
  public IAnswerData getAnswer() {
    clearFocus();
    return new DateData(new Date(date));
  }


  @Override
  public void setFocus(Context context) {
    // Hide the soft keyboard if it's showing.
    InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
    inputManager.hideSoftInputFromWindow(this.getWindowToken(), 0);
  }


  @Override
  public void setOnLongClickListener(OnLongClickListener l) {
    datePickerEditText.setOnLongClickListener(l);
  }


  @Override
  public void cancelLongPress() {
    super.cancelLongPress();
    datePickerEditText.cancelLongPress();
  }

  private void showDatePickerDialog() {
    final Calendar now = Calendar.getInstance();
    final Calendar defaultDate = Calendar.getInstance();

    if (date != DATE_UNSET) {
      defaultDate.setTimeInMillis(date);
    } else {
      defaultDate.setTime(now.getTime());
    }

    final int yearNow = defaultDate.get(Calendar.YEAR);
    final int monthNow = defaultDate.get(Calendar.MONTH); // Note: zero based!
    final int dayNow = defaultDate.get(Calendar.DAY_OF_MONTH);

    final DatePickerDialog dialog = new DatePickerDialog(getContext(), new DatePickerDialog.OnDateSetListener() {

      // This event is fired when the date is set on the
      // date picker.
      @Override
      public void onDateSet(final DatePicker view, final int year, final int monthOfYear, final int dayOfMonth) {
        final Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        calendar.set(Calendar.MONTH, monthOfYear);
        calendar.set(Calendar.YEAR, year);

        date = calendar.getTimeInMillis();
        final int flags = DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
        final String formattedDate = DateUtils.formatDateTime(getContext(), calendar.getTime().getTime(), flags);
        datePickerEditText.setText(formattedDate);
      }
    }, yearNow, monthNow, dayNow);

    dialog.setButton(DialogInterface.BUTTON_NEUTRAL, getContext().getString(R.string.date_picker_clear),
        new DialogInterface.OnClickListener() {
          @Override
          public void onClick(final DialogInterface dialog, final int which) {
            if (which == DialogInterface.BUTTON_NEUTRAL) {
              datePickerEditText.setText("");
              date = DATE_UNSET;
            }
          }
        });

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
      final CalendarView cal = dialog.getDatePicker().getCalendarView();
      if (cal != null) {
        final long current = cal.getDate();
        cal.setDate(cal.getMaxDate(), false, true);
        cal.setDate(current, false, true);
      }
    }

    dialog.show();
  }
}
