/*
 * Copyright (C) 2012 The CyanogenMod Project
 *
 * 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 com.cyanogenmod.filemanager.ui.preferences;

import android.content.Context;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.cyanogenmod.filemanager.R;
import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;

import java.util.List;

/**
 * A view that allow view all installed themes by scrolling horizontally.
 */
public class ThemeRoulette extends HorizontalScrollView {

    /**
     * An interface for raise theme selection events
     */
    public interface OnThemeScrollSelectionListener {
        /**
         * Method invoked when the scroll selection of a theme start
         */
        void onScrollSelectionStart();
        /**
         * Method invoked when a new scroll selection of a theme was made
         *
         * @param theme The new theme
         */
        void onScrollSelectionChanged(Theme theme);
    }

    /**
     * @hide
     */
    ViewGroup mRouletteLayout;
    private View mSpacer1;
    private View mSpacer2;

    /**
     * @hide
     */
    int mSpacerWidth;
    /**
     * @hide
     */
    int mThemeWidth;

    /**
     * @hide
     */
    int mCurrentThemePosition;

    /**
     * @hide
     */
    OnThemeScrollSelectionListener mOnThemeScrollSelectionListener;

    /**
     * Constructor of <code>ThemeRoulette</code>.
     *
     * @param context The current context
     */
    public ThemeRoulette(Context context) {
        super(context);
        init();
    }

    /**
     * Constructor of <code>ThemeRoulette</code>.
     *
     * @param context The current context
     * @param attrs The attributes of the XML tag that is inflating the view.
     */
    public ThemeRoulette(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    /**
     * Constructor of <code>ThemeRoulette</code>.
     *
     * @param context The current context
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @param defStyle The default style to apply to this view. If 0, no style
     *        will be applied (beyond what is included in the theme). This may
     *        either be an attribute resource, whose value will be retrieved
     *        from the current theme, or an explicit style resource.
     */
    public ThemeRoulette(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    /**
     * Method that initializes the view
     */
    private void init() {
        this.mRouletteLayout = (ViewGroup)inflate(getContext(), R.layout.theme_roulette, null);
        this.mRouletteLayout.setLayoutParams(
                new LinearLayout.LayoutParams(
                        ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));
        this.mSpacer1 = this.mRouletteLayout.findViewById(R.id.spacer1);
        this.mSpacer2 = this.mRouletteLayout.findViewById(R.id.spacer2);
        addView(this.mRouletteLayout);

        this.mCurrentThemePosition = -1;

        setSmoothScrollingEnabled(false);
    }

    /**
     * Method that sets the listener where return theme scroll selection changes
     *
     * @param onThemeScrollSelectionListener The listener
     */
    public void setOnThemeScrollSelectionListener(
            OnThemeScrollSelectionListener onThemeScrollSelectionListener) {
        this.mOnThemeScrollSelectionListener = onThemeScrollSelectionListener;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        this.setMeasuredDimension(parentWidth, parentHeight);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int mw = (int)getResources().getDimension(R.dimen.theme_max_width);
        int w =  (int)(getWidth() / 1.5);
        this.mSpacerWidth = (getWidth() - Math.min(w, mw)) / 2;
        this.mSpacer1.getLayoutParams().width = this.mSpacerWidth;
        this.mSpacer2.getLayoutParams().width = this.mSpacerWidth;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        // Detect the motion
        int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            break;

        case MotionEvent.ACTION_MOVE:
            if (this.mOnThemeScrollSelectionListener != null) {
                this.mOnThemeScrollSelectionListener.onScrollSelectionStart();
            }
            break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            post(new Runnable() {
                @Override
                public void run() {
                    int themeViewPosition = getVisibleThemeViewPosition();
                    if (themeViewPosition >= 1) {
                        ThemeRoulette.this.mCurrentThemePosition = themeViewPosition;
                        scrollToThemePosition(themeViewPosition, true);
                    }
                }
            });
            break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * Method that sets the themes of this roulette
     *
     * @param themes The themes of this roulette
     * @param currentTheme The current theme
     * @param scrollTo The theme to scroll to
     */
    public void setThemes(List<Theme> themes, Theme currentTheme, final int scrollTo) {
        int cc = themes.size();
        int pos = -1;
        for (int i = 0; i < cc; i++) {
            Theme theme = themes.get(i);
            addTheme(this.mRouletteLayout, theme);
            if (theme.compareTo(currentTheme) == 0) {
                pos = i + 1;
            }
        }

        // If the theme is found
        if (pos != -1) {
            final int childPos = pos;
            post(new Runnable() {
                @Override
                public void run() {
                    ThemeRoulette.this.mCurrentThemePosition =
                            (scrollTo > 0) ? scrollTo : childPos;
                    scrollToThemePosition(ThemeRoulette.this.mCurrentThemePosition, false);
                    markThemeAsDefault(childPos);
                }
            });
        }
    }

    /**
     * Method that adds a theme to the roulette
     *
     * @param root The root view
     * @param theme The theme to add
     */
    private void addTheme(ViewGroup root, Theme theme) {
        // Create the layout and assign its theme
        ThemeView v = (ThemeView)inflate(getContext(), R.layout.theme_view, null);
        int mw = (int)getResources().getDimension(R.dimen.theme_max_width);
        int w =  (int)(getWidth() / 1.5);
        this.mThemeWidth = Math.min(w, mw);
        v.setLayoutParams(
                new LinearLayout.LayoutParams(
                        this.mThemeWidth,
                        ViewGroup.LayoutParams.MATCH_PARENT));
        v.setTag(theme);

        // Set the view info
        TextView name = (TextView)v.findViewById(R.id.theme_name);
        name.setText(theme.getName());
        TextView author = (TextView)v.findViewById(R.id.theme_author);
        author.setText(theme.getAuthor());
        TextView desc = (TextView)v.findViewById(R.id.theme_desc);
        desc.setText(theme.getDescription());
        ImageView preview = (ImageView)v.findViewById(R.id.theme_preview);
        preview.setContentDescription(theme.getName());
        Drawable dw = theme.getPreviewImage(getContext());
        if (dw != null) {
            preview.setImageDrawable(dw);
        } else {
            dw = theme.getNoPreviewImage(getContext());
            preview.setImageDrawable(dw);
        }

        // Add to the end of the roulette
        root.addView(v, root.getChildCount()-1);
    }

    /**
     * Method that returns the visible theme view position, based on the position
     * on the screen (the most centered is the current view)
     *
     * @return int The visible theme view position
     * @hide
     */
    int getVisibleThemeViewPosition() {
        int[] rouletteSize = new int[2];
        this.getLocationOnScreen(rouletteSize);
        int x = rouletteSize[0] + (this.getWidth() / 2);
        int width = 0;

        int[] location = new int[2];
        int cc = this.mRouletteLayout.getChildCount()-1;
        for (int i = 1; i < cc; i++) {
            View v = this.mRouletteLayout.getChildAt(i);
            if (v instanceof ThemeView) {
                v.getLocationOnScreen(location);
                width = v.getWidth();
                if (location[0] <= x && x <= (location[0] + width)) {
                   return  i;
                }
            }
        }
        return -1;
    }

    /**
     * Method that scroll to the theme position
     *
     * @param position The position where to scroll
     * @param smooth Use a smooth scroll to position
     * @hide
     */
    void scrollToThemePosition(int position, boolean smooth) {
        if (position <= 0) return;
        int x = 0;
        if (position > 1) {
            x += ThemeRoulette.this.mThemeWidth * (position - 1);
        }
        if (smooth) {
            smoothScrollTo(x, 0);
        } else {
            scrollTo(x, 0);
        }

        // Notify the change
        if (ThemeRoulette.this.mOnThemeScrollSelectionListener != null) {
            ThemeView v =
                    (ThemeView)ThemeRoulette.this.mRouletteLayout.
                            getChildAt(position);
            ThemeRoulette.this.
                mOnThemeScrollSelectionListener.
                    onScrollSelectionChanged((Theme)v.getTag());
        }
    }

    /**
     * Method that mark the current visible theme as the default
     */
    void markCurrentVisibleThemeAsDefault() {
       int position = getVisibleThemeViewPosition();
       if (position >= 1) {
           markThemeAsDefault(position);
       }
    }

    /**
     * Method that mark the theme as the default
     *
     * @param position The position of the theme
     */
    void markThemeAsDefault(int position) {
        int cc = this.mRouletteLayout.getChildCount()-1;
        for (int i = 1; i < cc; i++) {
            ThemeView v =
                    (ThemeView)ThemeRoulette.this.mRouletteLayout.
                            getChildAt(i);
            if (i == position) {
                v.getName().setPaintFlags(
                        v.getName().getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
            } else {
                v.getName().setPaintFlags(
                        v.getName().getPaintFlags() & ~Paint.UNDERLINE_TEXT_FLAG);
            }
        }
    }
}
