/*
 * Copyright 2013 serso aka se.solovyev
 *
 * 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.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Contact details
 *
 * Email: se.solovyev@gmail.com
 * Site:  http://se.solovyev.org
 */

package org.solovyev.android.calculator;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v7.app.AlertDialog;
import android.view.*;
import butterknife.Bind;
import butterknife.ButterKnife;
import com.squareup.otto.Bus;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.math.NotDoubleException;
import org.solovyev.android.calculator.converter.ConverterFragment;
import org.solovyev.android.calculator.jscl.JsclOperation;

import javax.annotation.Nonnull;
import javax.inject.Inject;

public class DisplayFragment extends BaseFragment implements View.OnClickListener,
        MenuItem.OnMenuItemClickListener {

    private enum ConversionMenuItem {

        to_bin(NumeralBase.bin, R.string.convert_to_bin),
        to_dec(NumeralBase.dec, R.string.convert_to_dec),
        to_hex(NumeralBase.hex, R.string.convert_to_hex);

        @Nonnull
        public final NumeralBase toNumeralBase;
        public final int title;

        ConversionMenuItem(@Nonnull NumeralBase toNumeralBase, @StringRes int title) {
            this.toNumeralBase = toNumeralBase;
            this.title = title;
        }

        @Nullable
        public static ConversionMenuItem getByTitle(int title) {
            switch (title) {
                case R.string.convert_to_bin:
                    return to_bin;
                case R.string.convert_to_dec:
                    return to_dec;
                case R.string.convert_to_hex:
                    return to_hex;
            }
            return null;
        }
    }

    @Bind(R.id.calculator_display)
    DisplayView displayView;
    @Inject
    SharedPreferences preferences;
    @Inject
    ErrorReporter errorReporter;
    @Inject
    Display display;
    @Inject
    ActivityLauncher launcher;
    @Inject
    Bus bus;
    @Inject
    Calculator calculator;
    @Inject
    Engine engine;

    public DisplayFragment() {
        super(R.layout.cpp_app_display);
    }

    @Override
    protected void inject(@Nonnull AppComponent component) {
        super.inject(component);
        component.inject(this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View view = super.onCreateView(inflater, container, savedInstanceState);
        ButterKnife.bind(this, view);
        display.setView(displayView);
        displayView.setOnClickListener(this);
        return view;
    }

    @Override
    public void onDestroyView() {
        display.clearView(displayView);
        super.onDestroyView();
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
            ContextMenu.ContextMenuInfo menuInfo) {
        final DisplayState state = display.getState();
        if (!state.valid) {
            return;
        }
        addMenu(menu, R.string.cpp_copy, this);

        final Generic result = state.getResult();
        final JsclOperation operation = state.getOperation();
        if (result != null) {
            if (operation == JsclOperation.numeric && result.getConstants().isEmpty()) {
                for (ConversionMenuItem item : ConversionMenuItem.values()) {
                    if (isMenuItemVisible(item, result)) {
                        addMenu(menu, item.title, this);
                    }
                }
                try {
                    result.doubleValue();
                    addMenu(menu, R.string.c_convert, this);
                } catch (NotDoubleException ignored) {
                }
            }
            if (launcher.canPlot(result)) {
                addMenu(menu, R.string.c_plot, this);
            }
        }
    }

    protected boolean isMenuItemVisible(@NonNull ConversionMenuItem menuItem,
            @Nonnull Generic generic) {
        final NumeralBase fromNumeralBase = engine.getMathEngine().getNumeralBase();
        if (fromNumeralBase != menuItem.toNumeralBase) {
            return calculator.canConvert(generic, fromNumeralBase, menuItem.toNumeralBase);
        }

        return false;
    }

    @Override
    public void onClick(View v) {
        final DisplayState state = display.getState();
        if (state.valid) {
            v.setOnCreateContextMenuListener(this);
            v.showContextMenu();
            v.setOnCreateContextMenuListener(null);
        } else {
            showEvaluationError(v.getContext(), state.text);
        }
    }

    public static void showEvaluationError(@Nonnull Context context,
                                           @Nonnull final String errorMessage) {
        new AlertDialog.Builder(context, App.getTheme().alertDialogTheme)
                .setPositiveButton(R.string.cpp_cancel, null)
                .setMessage(errorMessage).create().show();
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        final DisplayState state = display.getState();
        final Generic result = state.getResult();
        switch (item.getItemId()) {
            case R.string.cpp_copy:
                display.copy();
                return true;
            case R.string.convert_to_bin:
            case R.string.convert_to_dec:
            case R.string.convert_to_hex:
                final ConversionMenuItem menuItem = ConversionMenuItem.getByTitle(item.getItemId());
                if (menuItem == null) {
                    return false;
                }
                if (result != null) {
                    calculator.convert(state, menuItem.toNumeralBase);
                }
                return true;
            case R.string.c_convert:
                ConverterFragment.show(getActivity(), getValue(result));
                return true;
            case R.string.c_plot:
                launcher.plot(result);
                return true;
            default:
                return false;
        }
    }

    private static double getValue(@Nullable Generic result) {
        if (result == null) {
            return 1d;
        }
        try {
            return result.doubleValue();
        } catch (NotDoubleException ignored) {
            return 1d;
        }
    }
}
