/*
 * Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
 *
 * 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 greendroid.widget;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;

import com.cyrilmottier.android.greendroid.R;

/**
 * Abstraction of a {@link QuickAction} wrapper. A QuickActionWidget is
 * displayed on top of the user interface (it overlaps all UI elements but the
 * notification bar). Clients may listen to user actions using a
 * {@link OnQuickActionClickListener} .
 *
 * @author Benjamin Fellous
 * @author Cyril Mottier
 */
public abstract class QuickActionWidget extends PopupWindow {

    private static final int MEASURE_AND_LAYOUT_DONE = 1 << 1;

    private final int[] mLocation = new int[2];
    protected final Rect mRect = new Rect();

    private int mPrivateFlags;

    private Context mContext;

    private boolean mDismissOnClick;
    private int mArrowOffsetY;

    private int mPopupY;
    private boolean mIsOnTop;

    private int mScreenHeight;
    private int mScreenWidth;
    private boolean mIsDirty;

    private OnQuickActionClickListener mOnQuickActionClickListener;
    private ArrayList<QuickAction> mQuickActions = new ArrayList<QuickAction>();

    /**
     * Interface that may be used to listen to clicks on quick actions.
     *
     * @author Benjamin Fellous
     * @author Cyril Mottier
     */
    public static interface OnQuickActionClickListener {
        /**
         * Clients may implement this method to be notified of a click on a
         * particular quick action.
         *
         * @param position Position of the quick action that have been clicked.
         */
        void onQuickActionClicked(QuickActionWidget widget, int position);
    }

    /**
     * Creates a new QuickActionWidget for the given context.
     *
     * @param context The context in which the QuickActionWidget is running in
     */
    public QuickActionWidget(Context context) {
        super(context);

        mContext = context;

        initializeDefault();

        setFocusable(true);
        setTouchable(true);
        setOutsideTouchable(true);
        setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
        setHeight(WindowManager.LayoutParams.WRAP_CONTENT);

        final WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        mScreenWidth = windowManager.getDefaultDisplay().getWidth();
        mScreenHeight = windowManager.getDefaultDisplay().getHeight();
    }

    /**
     * Equivalent to {@link PopupWindow#setContentView(View)} but with a layout
     * identifier.
     *
     * @param layoutId The layout identifier of the view to use.
     */
    public void setContentView(int layoutId) {
        setContentView(LayoutInflater.from(mContext).inflate(layoutId, null));
    }

    private void initializeDefault() {
        mDismissOnClick = true;
        mArrowOffsetY = mContext.getResources().getDimensionPixelSize(R.dimen.gd_arrow_offset);
    }

    /**
     * Returns the arrow offset for the Y axis.
     *
     * @see {@link #setArrowOffsetY(int)}
     * @return The arrow offset.
     */
    public int getArrowOffsetY() {
        return mArrowOffsetY;
    }

    /**
     * Sets the arrow offset to a new value. Setting an arrow offset may be
     * particular useful to warn which view the QuickActionWidget is related to.
     * By setting a positive offset, the arrow will overlap the view given by
     * {@link #show(View)}. The default value is 5dp.
     *
     * @param offsetY The offset for the Y axis
     */
    public void setArrowOffsetY(int offsetY) {
        mArrowOffsetY = offsetY;
    }

    /**
     * Returns the width of the screen.
     *
     * @return The width of the screen
     */
    protected int getScreenWidth() {
        return mScreenWidth;
    }

    /**
     * Returns the height of the screen.
     *
     * @return The height of the screen
     */
    protected int getScreenHeight() {
        return mScreenHeight;
    }

    /**
     * By default, a {@link QuickActionWidget} is dismissed once the user
     * clicked on a {@link QuickAction}. This behavior can be changed using this
     * method.
     *
     * @param dismissOnClick True if you want the {@link QuickActionWidget} to
     *            be dismissed on click else false.
     */
    public void setDismissOnClick(boolean dismissOnClick) {
        mDismissOnClick = dismissOnClick;
    }

    public boolean getDismissOnClick() {
        return mDismissOnClick;
    }

    /**
     * @param listener
     */
    public void setOnQuickActionClickListener(OnQuickActionClickListener listener) {
        mOnQuickActionClickListener = listener;
    }

    /**
     * Add a new QuickAction to this {@link QuickActionWidget}. Adding a new
     * {@link QuickAction} while the {@link QuickActionWidget} is currently
     * being shown does nothing. The new {@link QuickAction} will be displayed
     * on the next call to {@link #show(View)}.
     *
     * @param action The new {@link QuickAction} to add
     */
    public void addQuickAction(QuickAction action) {
        if (action != null) {
            mQuickActions.add(action);
            mIsDirty = true;
        }
    }

    /**
     * Removes all {@link QuickAction} from this {@link QuickActionWidget}.
     */
    public void clearAllQuickActions() {
        if (!mQuickActions.isEmpty()) {
            mQuickActions.clear();
            mIsDirty = true;
        }
    }

    /**
     * Call that method to display the {@link QuickActionWidget} anchored to the
     * given view.
     *
     * @param anchor The view the {@link QuickActionWidget} will be anchored to.
     */
    public void show(View anchor) {

        final View contentView = getContentView();

        if (contentView == null) {
            throw new IllegalStateException("You need to set the content view using the setContentView method");
        }

        // Replaces the background of the popup with a cleared background
        setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        final int[] loc = mLocation;
        anchor.getLocationOnScreen(loc);
        mRect.set(loc[0], loc[1], loc[0] + anchor.getWidth(), loc[1] + anchor.getHeight());

        if (mIsDirty) {
            clearQuickActions();
            populateQuickActions(mQuickActions);
        }

        onMeasureAndLayout(mRect, contentView);

        if ((mPrivateFlags & MEASURE_AND_LAYOUT_DONE) != MEASURE_AND_LAYOUT_DONE) {
            throw new IllegalStateException("onMeasureAndLayout() did not set the widget specification by calling"
                    + " setWidgetSpecs()");
        }

        showArrow();
        prepareAnimationStyle();

        try {
            showAtLocation(anchor, Gravity.NO_GRAVITY, getShowAtX(), mPopupY);
        } catch (Exception e) {
            Log.w("quick-action-show", e);
        }
    }
    
    protected int getShowAtX() {
    	return 0;
    }

    protected void clearQuickActions() {
        if (!mQuickActions.isEmpty()) {
            onClearQuickActions();
        }
    }

    protected void onClearQuickActions() {
    }

    protected abstract void populateQuickActions(List<QuickAction> quickActions);

    protected abstract void onMeasureAndLayout(Rect anchorRect, View contentView);

    protected void setWidgetSpecs(int popupY, boolean isOnTop) {
        mPopupY = popupY;
        mIsOnTop = isOnTop;

        mPrivateFlags |= MEASURE_AND_LAYOUT_DONE;
    }

    private void showArrow() {

        final View contentView = getContentView();
        final int arrowId = mIsOnTop ? R.id.gdi_arrow_down : R.id.gdi_arrow_up;
        final View arrow = contentView.findViewById(arrowId);
        final View arrowUp = contentView.findViewById(R.id.gdi_arrow_up);
        final View arrowDown = contentView.findViewById(R.id.gdi_arrow_down);

        if (arrowId == R.id.gdi_arrow_up) {
            arrowUp.setVisibility(View.VISIBLE);
            arrowDown.setVisibility(View.INVISIBLE);
        } else if (arrowId == R.id.gdi_arrow_down) {
            arrowUp.setVisibility(View.INVISIBLE);
            arrowDown.setVisibility(View.VISIBLE);
        }

        ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) arrow.getLayoutParams();
        param.leftMargin = getArrowLeftMargin(arrow);
    }
    
    protected int getArrowLeftMargin(View arrow) {
    	return mRect.centerX() - (arrow.getMeasuredWidth()) / 2;    	
    }

    private void prepareAnimationStyle() {

        final int screenWidth = mScreenWidth;
        final boolean onTop = mIsOnTop;
        final int arrowPointX = mRect.centerX();

        if (arrowPointX <= screenWidth / 4) {
            setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Left
                    : R.style.GreenDroid_Animation_PopDown_Left);
        } else if (arrowPointX >= 3 * screenWidth / 4) {
            setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Right
                    : R.style.GreenDroid_Animation_PopDown_Right);
        } else {
            setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Center
                    : R.style.GreenDroid_Animation_PopDown_Center);
        }
    }

    protected Context getContext() {
        return mContext;
    }

    protected OnQuickActionClickListener getOnQuickActionClickListener() {
        return mOnQuickActionClickListener;
    }
}
