/*
 * Copyright 2019 Sergey Ivanov
 *
 * 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.sergivonavi.materialbanner.internal;

import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.ViewGroup;

import com.google.android.material.button.MaterialButton;
import com.sergivonavi.materialbanner.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import androidx.annotation.DimenRes;
import androidx.annotation.IntDef;
import androidx.annotation.RestrictTo;
import androidx.core.view.ViewCompat;

import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;

@RestrictTo(RestrictTo.Scope.LIBRARY)
public class ButtonsContainer extends ViewGroup {

    @IntDef({HORIZONTAL, VERTICAL})
    @Retention(RetentionPolicy.SOURCE)
    private @interface OrientationMode {}

    public static final int HORIZONTAL = 0;
    public static final int VERTICAL = 1;

    private MaterialButton mLeftButton;
    private MaterialButton mRightButton;

    private int mButtonMarginEnd;
    private int mButtonMarginBottom;

    private int mOrientation;

    public ButtonsContainer(Context context) {
        this(context, null);
    }

    public ButtonsContainer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ButtonsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mButtonMarginEnd = getDimen(R.dimen.mb_button_margin_end);
        mButtonMarginBottom = getDimen(R.dimen.mb_button_margin_bottom);

        MarginLayoutParams layoutParams = new MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            layoutParams.setMarginEnd(mButtonMarginEnd);
        } else {
            layoutParams.rightMargin = mButtonMarginEnd;
        }
        layoutParams.bottomMargin = mButtonMarginBottom;

        mLeftButton = new MaterialButton(context, null, R.attr.borderlessButtonStyle);
        mLeftButton.setId(R.id.mb_button_left);
        mLeftButton.setSingleLine(true);
        mLeftButton.setMaxLines(1);
        mLeftButton.setMinWidth(0);
        mLeftButton.setMinimumWidth(0);
        mLeftButton.setLayoutParams(layoutParams);
        mLeftButton.setVisibility(GONE);

        mRightButton = new MaterialButton(context, null, R.attr.borderlessButtonStyle);
        mRightButton.setId(R.id.mb_button_right);
        mRightButton.setSingleLine(true);
        mRightButton.setMaxLines(1);
        mRightButton.setMinWidth(0);
        mRightButton.setMinimumWidth(0);
        mRightButton.setLayoutParams(layoutParams);
        mRightButton.setVisibility(GONE);

        addView(mLeftButton);
        addView(mRightButton);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthUsed = 0;

        if (mLeftButton.getVisibility() != GONE) {
            measureChildWithMargins(mLeftButton, widthMeasureSpec, 0, heightMeasureSpec, 0);
            widthUsed += mLeftButton.getMeasuredWidth() + mButtonMarginEnd;
        }

        if (mRightButton.getVisibility() != GONE) {
            measureChildWithMargins(mRightButton, widthMeasureSpec, 0, heightMeasureSpec, 0);
            widthUsed += mRightButton.getMeasuredWidth() + mButtonMarginEnd;
        }

        // Allow orientation change only when the both buttons are not hidden
        if (mLeftButton.getVisibility() != GONE && mRightButton.getVisibility() != GONE) {
            if (widthUsed > MeasureSpec.getSize(widthMeasureSpec)) {
                mOrientation = VERTICAL;
            } else {
                mOrientation = HORIZONTAL;
            }
        }

        if (mOrientation == VERTICAL) {
            measureVertical();
        } else {
            measureHorizontal();
        }
    }

    /**
     * Measures the children when the orientation of this view is set to {@link #VERTICAL}.
     */
    private void measureVertical() {
        int widthUsed = 0;
        int heightUsed = 0;

        if (mLeftButton.getVisibility() != GONE) {
            widthUsed = mLeftButton.getMeasuredWidth() + mButtonMarginEnd;
            heightUsed += mLeftButton.getMeasuredHeight() + mButtonMarginBottom;
        }

        if (mRightButton.getVisibility() != GONE) {
            widthUsed = Math.max(widthUsed, mRightButton.getMeasuredWidth() + mButtonMarginEnd);
            heightUsed += mRightButton.getMeasuredHeight() + mButtonMarginBottom;
        }

        setMeasuredDimension(widthUsed, heightUsed);
    }

    /**
     * Measures the children when the orientation of this view is set to {@link #HORIZONTAL}.
     */
    private void measureHorizontal() {
        int widthUsed = 0;
        int heightUsed = 0;

        if (mLeftButton.getVisibility() != GONE) {
            widthUsed += mLeftButton.getMeasuredWidth() + mButtonMarginEnd;
            heightUsed = mLeftButton.getMeasuredHeight() + mButtonMarginBottom;
        }

        if (mRightButton.getVisibility() != GONE) {
            widthUsed += mRightButton.getMeasuredWidth() + mButtonMarginEnd;
            heightUsed = Math.max(heightUsed,
                    mRightButton.getMeasuredHeight() + mButtonMarginBottom);
        }

        setMeasuredDimension(widthUsed, heightUsed);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (mOrientation == VERTICAL) {
            layoutVertical();
        } else {
            layoutHorizontal();
        }
    }

    /**
     * Position the children during a layout pass if the orientation of this view is set to
     * {@link #VERTICAL}.
     */
    private void layoutVertical() {
        int top = 0;
        int lBtnRight = getMeasuredWidth() - mButtonMarginEnd;
        int lBtnLeft = lBtnRight - mLeftButton.getMeasuredWidth();
        int rBtnRight = getMeasuredWidth() - mButtonMarginEnd;
        int rBtnLeft = rBtnRight - mRightButton.getMeasuredWidth();

        if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
            lBtnLeft = mButtonMarginEnd;
            lBtnRight = lBtnLeft + mLeftButton.getMeasuredWidth();
            rBtnLeft = mButtonMarginEnd;
            rBtnRight = rBtnLeft + mRightButton.getMeasuredWidth();
        }

        if (mRightButton.getVisibility() != GONE) {
            mRightButton.layout(rBtnLeft, top, rBtnRight, mRightButton.getMeasuredHeight());
            top += mRightButton.getMeasuredHeight() + mButtonMarginBottom;
        }

        if (mLeftButton.getVisibility() != GONE) {
            mLeftButton.layout(lBtnLeft, top, lBtnRight, top + mLeftButton.getMeasuredHeight());
        }
    }

    /**
     * Position the children during a layout pass if the orientation of this view is set to
     * {@link #HORIZONTAL}.
     */
    private void layoutHorizontal() {
        int lBtnRight = mLeftButton.getMeasuredWidth();
        int lBtnLeft = 0;
        int rBtnRight = getMeasuredWidth() - mButtonMarginEnd;
        int rBtnLeft = rBtnRight - mRightButton.getMeasuredWidth();

        if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
            rBtnLeft = mButtonMarginEnd;
            rBtnRight = rBtnLeft + mRightButton.getMeasuredWidth();
            lBtnRight = getMeasuredWidth();
            lBtnLeft = lBtnRight - mLeftButton.getMeasuredWidth();
        }

        if (mLeftButton.getVisibility() != GONE) {
            mLeftButton.layout(lBtnLeft, 0, lBtnRight, mLeftButton.getMeasuredHeight());
        }

        if (mRightButton.getVisibility() != GONE) {
            mRightButton.layout(rBtnLeft, 0, rBtnRight, mRightButton.getMeasuredHeight());
        }
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof MarginLayoutParams;
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    /**
     * Returns the baseline of the left button if it's not hidden or the baseline of the right
     * button. If both buttons hidden returns -1.
     */
    @Override
    public int getBaseline() {
        if (mLeftButton.getVisibility() != GONE && mLeftButton.getText() != null) {
            return mLeftButton.getBaseline();
        } else if (mRightButton.getVisibility() != GONE && mRightButton.getText() != null) {
            return mRightButton.getBaseline();
        }
        return -1;
    }

    /**
     * Should the layout be a column or a row.
     *
     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}. Default value is
     *                    {@link #HORIZONTAL}.
     */
    public void setOrientation(@OrientationMode int orientation) {
        if (mOrientation != orientation) {
            mOrientation = orientation;
            requestLayout();
        }
    }

    /**
     * Returns the current orientation.
     *
     * @return either {@link #HORIZONTAL} or {@link #VERTICAL}
     */
    @OrientationMode
    public int getOrientation() {
        return mOrientation;
    }

    public MaterialButton getLeftButton() {
        return mLeftButton;
    }

    public MaterialButton getRightButton() {
        return mRightButton;
    }

    private int getDimen(@DimenRes int dimenId) {
        return getContext().getResources().getDimensionPixelSize(dimenId);
    }
}