/*
 * Copyright Txus Ballesteros 2016 (@txusballesteros)
 *
 * This file is part of some open source application.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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: Txus Ballesteros <[email protected]>
 */
package com.redbooth;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.LayoutRes;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;

import com.redbooth.welcomecoordinator.R;

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

public class WelcomeCoordinatorLayout extends HorizontalScrollView {
    public static final boolean ANIMATED  = true;
    public static final boolean INANIMATED  = false;
    public static final int WITHOUT_MARGIN = 0;
    public static final int RADIUS = 12;
    public static final int RADIUS_MARGIN = 30;
    public static final int DEF_INDICATOR_UNSELECTED_COLOR = Color.WHITE;
    public static final int DEF_INDICATOR_SELECTED_COLOR = Color.BLACK;
    private WelcomeCoordinatorTouchController touchController;
    private WelcomeCoordinatorPageInflater pageInflater;
    private FrameLayout mainContentView;
    private List<WelcomePageBehavior> behaviors = new ArrayList<>();
    private OnPageScrollListener onPageScrollListener;
    private int pageSelected = 0;
    private int indicatorColorUnselected = DEF_INDICATOR_UNSELECTED_COLOR;
    private int indicatorColorSelected = DEF_INDICATOR_SELECTED_COLOR;
    private Paint indicatorPaintUnselected;
    private Paint indicatorPaintSelected;
    private boolean showIndicators = true;
    private boolean scrollingEnabled = true;

    public WelcomeCoordinatorLayout(Context context) {
        super(context);
        initializeView(context, null);
    }

    public WelcomeCoordinatorLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initializeView(context, attrs);
    }

    public WelcomeCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initializeView(context, attrs);
    }

    @Override
    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
        return true;
    }

    public void showIndicators(boolean show) {
        this.showIndicators = show;
    }

    public void setScrollingEnabled(boolean enabled) {
        this.scrollingEnabled = enabled;
    }

    @SuppressWarnings("unused")
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public WelcomeCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initializeView(context, attrs);
    }

    public void addPage(@LayoutRes int... layoutResourceIds) {
        for (int i = layoutResourceIds.length - 1; i >= 0; i--) {
            int layoutResourceId = layoutResourceIds[i];
            final View pageView = pageInflater.inflate(layoutResourceId);
            final List<WelcomePageBehavior> pageBehaviors = extractPageBehaviors(pageView);
            if (!pageBehaviors.isEmpty()) {
                this.behaviors.addAll(pageBehaviors);
            }
            mainContentView.addView(pageView);
        }
        if (onPageScrollListener != null) {
            onPageScrollListener.onPageSelected(this, 0);
        }
        requestLayout();
    }

    private List<WelcomePageBehavior> extractPageBehaviors(View view) {
        List<WelcomePageBehavior> behaviors = new ArrayList<>();
        if (view instanceof WelcomePageLayout) {
            final WelcomePageLayout pageLayout = (WelcomePageLayout)view;
            final List<WelcomePageBehavior> pageBehaviors = pageLayout.getBehaviors(this);
            if (!pageBehaviors.isEmpty()) {
                behaviors.addAll(pageBehaviors);
            }

        }
        return behaviors;
    }

    public int getNumOfPages() {
        int result = 0;
        if (mainContentView != null) {
            result = mainContentView.getChildCount();
        }
        return result;
    }

    private void initializeView(Context context, AttributeSet attrs) {
        this.setHorizontalScrollBarEnabled(false);
        this.setOverScrollMode(OVER_SCROLL_NEVER);
        touchController = new WelcomeCoordinatorTouchController(this);
        pageInflater = new WelcomeCoordinatorPageInflater(this);
        extractAttributes(context, attrs);
        buildMainContentView();
        attachMainContentView();
        configureIndicatorColors();
    }

    private void extractAttributes(Context context, AttributeSet attrs) {
        final TypedArray attributes
                = context.obtainStyledAttributes(attrs, R.styleable.WelcomeCoordinatorLayout);
        indicatorColorUnselected = attributes
                .getColor(R.styleable.WelcomeCoordinatorLayout_indicatorUnselected, DEF_INDICATOR_UNSELECTED_COLOR);
        indicatorColorSelected = attributes
                .getColor(R.styleable.WelcomeCoordinatorLayout_indicatorSelected, DEF_INDICATOR_SELECTED_COLOR);
        showIndicators = attributes
                .getBoolean(R.styleable.WelcomeCoordinatorLayout_showIndicators, showIndicators);
        scrollingEnabled = attributes
                .getBoolean(R.styleable.WelcomeCoordinatorLayout_scrollingEnabled, scrollingEnabled);
        attributes.recycle();
    }

    private void buildMainContentView() {
        mainContentView = new FrameLayout(this.getContext());
        mainContentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.MATCH_PARENT));
        mainContentView.setClipToPadding(false);
        mainContentView.setClipChildren(false);
    }

    private void attachMainContentView() {
        removeAllViews();
        setClipChildren(false);
        addView(mainContentView);
    }

    private void configureIndicatorColors() {
        indicatorPaintUnselected = new Paint();
        indicatorPaintUnselected.setColor(indicatorColorUnselected);
        indicatorPaintSelected = new Paint();
        indicatorPaintSelected.setColor(indicatorColorSelected);
    }

    public void setIndicatorColorSelected(int indicatorColorSelected) {
        this.indicatorColorSelected = indicatorColorSelected;
        indicatorPaintSelected.setColor(indicatorColorSelected);
    }

    public void setIndicatorColorUnselected(int indicatorColorUnselected) {
        this.indicatorColorUnselected = indicatorColorUnselected;
        indicatorPaintUnselected.setColor(indicatorColorUnselected);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        for (int index = 0; index < getNumOfPages(); index++) {
            ViewGroup childAt = (ViewGroup) mainContentView.getChildAt(index);
            configurePageLayout(childAt, index);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void configurePageLayout(ViewGroup pageView, int position) {
        int coordinatorWidth = getMeasuredWidth();
        int reversePosition = getNumOfPages() - 1 - position;
        int pageMarginLeft = (coordinatorWidth * reversePosition);
        int originalHeight = pageView.getLayoutParams().height;
        LayoutParams layoutParams = new LayoutParams(coordinatorWidth, originalHeight);
        layoutParams.setMargins(pageMarginLeft, WITHOUT_MARGIN, WITHOUT_MARGIN, WITHOUT_MARGIN);
        pageView.setLayoutParams(layoutParams);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (showIndicators) {
            drawIndicator(canvas);
        }
    }

    private void drawIndicator(Canvas canvas) {
        int centerX = (getWidth() - RADIUS)/2 + RADIUS/2;
        int indicatorWidth = RADIUS * 2;
        int indicatorAndMargin = indicatorWidth + RADIUS_MARGIN;
        int leftIndicators = centerX - ((getNumOfPages()-1) * indicatorAndMargin) / 2 ;
        int positionY = getHeight() - RADIUS - RADIUS_MARGIN;
        for (int i = 0; i < getNumOfPages(); i++) {
            int x = leftIndicators + indicatorAndMargin * i + getScrollX();
            canvas.drawCircle(x, positionY, RADIUS, indicatorPaintUnselected);
        }
        float width = (float) getWidth();
        float scrollProgress = getScrollX() / width;
        float selectedXPosition = leftIndicators + getScrollX() + scrollProgress * indicatorAndMargin;
        canvas.drawCircle(selectedXPosition, positionY, RADIUS, indicatorPaintSelected);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean touchEventCaptured = false;
        if (scrollingEnabled) {
            touchEventCaptured = touchController.onTouchEvent(event);
            if (!touchEventCaptured) {
                touchEventCaptured = super.onTouchEvent(event);
            }
        }
        return touchEventCaptured;
    }

    public void notifyProgressScroll(float progress, float scroll) {
        for (WelcomePageBehavior welcomePageBehavior : behaviors) {
            welcomePageBehavior.onPlaytimeChange(this, progress, scroll);
        }
    }

    public void setOnPageScrollListener(OnPageScrollListener onPageScrollListener) {
        this.onPageScrollListener = onPageScrollListener;
        touchController.setOnPageScrollListener(new WelcomeCoordinatorTouchController.OnPageScrollListener() {
            @Override
            public void onScrollPage(float progress) {
                int numOfPages = (getNumOfPages() - 1);
                int maximumScroll = getMeasuredWidth() * numOfPages;
                WelcomeCoordinatorLayout.this.onPageScrollListener.onScrollPage(WelcomeCoordinatorLayout.this, progress, maximumScroll);
            }

            @Override
            public void onPageSelected(int pageSelected) {
                WelcomeCoordinatorLayout.this.pageSelected = pageSelected;
                WelcomeCoordinatorLayout.this.onPageScrollListener.onPageSelected(WelcomeCoordinatorLayout.this, pageSelected);
            }
        });
    }

    public int getPageSelected() {
        return pageSelected;
    }

    public void setCurrentPage(int newCurrentPage, boolean animated) {
        pageSelected = Math.max(0, Math.min(getNumOfPages() -1, newCurrentPage));
        touchController.scrollToPage(pageSelected, animated);
    }

    public interface OnPageScrollListener {
        void onScrollPage(View v, float progress, float maximum);
        void onPageSelected(View v, int pageSelected);
    }
}