package com.quran.labs.androidquran.view;

/*
 * Copyright (C) 2013 The Android Open Source 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.
 */

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
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.quran.labs.androidquran.R;

import java.util.Locale;

/**
 * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
 * the user's scroll progress.
 * <p>
 * To use the component, simply add it to your view hierarchy. Then in your
 * {@link android.app.Activity} or {@link Fragment} call
 * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
 * <p>
 * The colors can be customized in two ways. The first and simplest is to provide an array of colors
 * via {@link #setSelectedIndicatorColors(int...)}. The alternative is via the {@link TabColorizer}
 * interface which provides you complete control over which color is used for any individual
 * position.
 *
 * <p>
 * The views used as tabs can be customized by calling ,
 * providing the layout ID of your custom layout.
 *
 * Modified for Quran Android to evenly distribute tabs, while allowing
 * horizontal scrolling when it makes sense.
 */
public class SlidingTabLayout extends HorizontalScrollView {

  /**
   * Allows complete control over the colors drawn in the tab layout. Set with
   * {@link #setCustomTabColorizer(TabColorizer)}.
   */
  interface TabColorizer {

    /**
     * @return return the color of the indicator used when {@code position} is selected.
     */
    int getIndicatorColor(int position);
  }

  private static final int TITLE_OFFSET_DIPS = 24;
  private static final int TAB_VIEW_PADDING_DIPS = 16;
  private static final int TAB_VIEW_TEXT_SIZE_SP = 12;

  private final int mTitleOffset;
  private final int mTabPadding;

  private int mTabViewLayoutId;
  private int mTabViewTextViewId;
  private int mTabViewImageViewId;
  private final int mSelectedTabColor;
  private final int mUnselectedTabColor;

  private ViewPager mViewPager;
  private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;

  private final SlidingTabStrip mTabStrip;

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

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

  public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    // Disable the Scroll Bar
    setHorizontalScrollBarEnabled(false);
    // Make sure that the Tab Strips fills this View
    setFillViewport(true);

    final Resources resources = getResources();
    final float density = resources.getDisplayMetrics().density;
    mTitleOffset = (int) (TITLE_OFFSET_DIPS * density);
    mTabPadding = (int) (TAB_VIEW_PADDING_DIPS * density);

    mSelectedTabColor = ContextCompat.getColor(context, R.color.accent_color_light);
    mUnselectedTabColor = ContextCompat.getColor(context, R.color.color_control_normal);

    mTabStrip = new SlidingTabStrip(context);
    mTabStrip.setSelectedIndicatorColors(ContextCompat.getColor(context, R.color.indicator_color));
    addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
  }

  /**
   * Set the custom {@link TabColorizer} to be used.
   *
   * If you only require simple customization then you can use
   * {@link #setSelectedIndicatorColors(int...)} to achieve
   * similar effects.
   */
  public void setCustomTabColorizer(TabColorizer tabColorizer) {
    mTabStrip.setCustomTabColorizer(tabColorizer);
  }

  /**
   * Sets the colors to be used for indicating the selected tab. These colors are treated as a
   * circular array. Providing one color will mean that all tabs are indicated with the same color.
   */
  public void setSelectedIndicatorColors(int... colors) {
    mTabStrip.setSelectedIndicatorColors(colors);
  }

  /**
   * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
   * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
   * that the layout can update it's scroll position correctly.
   *
   * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
   */
  public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
    mViewPagerPageChangeListener = listener;
  }

  /**
   * Set the custom layout to be inflated for the tab views.
   *
   * @param layoutResId Layout id to be inflated
   * @param textViewId id of the {@link TextView} in the inflated view
   */
  public void setCustomTabView(int layoutResId, int textViewId, int imageViewId) {
    mTabViewLayoutId = layoutResId;
    mTabViewTextViewId = textViewId;
    mTabViewImageViewId = imageViewId;
  }

  /**
   * Sets the associated view pager. Note that the assumption here is that the pager content
   * (number of tabs and tab titles) does not change after this call has been made.
   */
  public void setViewPager(ViewPager viewPager) {
    mTabStrip.removeAllViews();

    mViewPager = viewPager;
    if (viewPager != null) {
      viewPager.addOnPageChangeListener(new InternalViewPagerListener());
      populateTabStrip();
      updateTabsTextColor();
    }
  }

  /**
   * Create a default view to be used for tabs. This is called if a custom tab view is not set via
   * .
   */
  protected TextView createDefaultTabView(Context context) {
    TextView textView = new TextView(context);
    textView.setGravity(Gravity.CENTER);
    textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
    textView.setTypeface(Typeface.DEFAULT_BOLD);
    textView.setSingleLine();
    textView.setTextColor(mUnselectedTabColor);

    // If we're running on Honeycomb or newer, then we can use the Theme's
    // selectableItemBackground to ensure that the View has a pressed state
    TypedValue outValue = new TypedValue();
    getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
        outValue, true);
    textView.setBackgroundResource(outValue.resourceId);
    textView.setAllCaps(true);

    int padding = mTabPadding;
    textView.setPadding(padding, padding, padding, padding);

    return textView;
  }

  private void populateTabStrip() {
    final PagerAdapter adapter = mViewPager.getAdapter();
    final View.OnClickListener tabClickListener = new TabClickListener();

    final DisplayMetrics metrics = getResources().getDisplayMetrics();
    final float fontSize = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP, metrics);
    final TextPaint paint = new TextPaint();
    paint.setTextSize(fontSize);
    paint.setTypeface(Typeface.DEFAULT_BOLD);

    int targetWidth = 0;
    final int tabs = adapter.getCount();
    for (int i = 0; i < tabs; i++) {
      String str = adapter.getPageTitle(i).toString();
      str = str.toUpperCase(Locale.getDefault());

      int width = (int) paint.measureText(str);
      width = width + 2 * mTabPadding;
      if (width > targetWidth) {
        targetWidth = width;
      }
    }

    if (targetWidth * tabs < metrics.widthPixels) {
      targetWidth = metrics.widthPixels / tabs;
    }

    for (int i = 0; i < adapter.getCount(); i++) {
      View tabView = null;
      TextView tabTitleView = null;
      ImageView tabImageView = null;

      if (mTabViewLayoutId != 0) {
        // If there is a custom tab view layout id set, try and inflate it
        tabView = LayoutInflater.from(getContext())
            .inflate(mTabViewLayoutId, mTabStrip, false);
        tabTitleView = tabView.findViewById(mTabViewTextViewId);
        tabImageView = tabView.findViewById(mTabViewImageViewId);
      }

      if (tabView == null) {
        tabView = createDefaultTabView(getContext());
      }

      if (tabTitleView == null && TextView.class.isInstance(tabView)) {
        tabTitleView = (TextView) tabView;
      }

      if (tabTitleView != null) {
        tabTitleView.setText(adapter.getPageTitle(i));
      }

      if (tabImageView != null) {
        tabImageView.setImageResource(getIconForTab(i));
      }
      tabView.setOnClickListener(tabClickListener);

      final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
          targetWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
      mTabStrip.addView(tabView, params);
    }
  }

  private int getIconForTab(int position) {
    switch (position) {
      case 0:
        return R.drawable.article;
      case 1:
        return R.drawable.library_books;
      case 2:
        return R.drawable.bookmarks;
      // Add cases for other tabs
      default:
        return R.drawable.article;  // Default icon if position doesn't match
    }
  }

  @Override
  protected void onAttachedToWindow() {
    super.onAttachedToWindow();

    if (mViewPager != null) {
      scrollToTab(mViewPager.getCurrentItem(), 0);
    }
  }

  private void scrollToTab(int tabIndex, int positionOffset) {
    final int tabStripChildCount = mTabStrip.getChildCount();
    if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
      return;
    }

    View selectedChild = mTabStrip.getChildAt(tabIndex);
    if (selectedChild != null) {
      int targetScrollX = selectedChild.getLeft() + positionOffset;

      if (tabIndex > 0 || positionOffset > 0) {
        // If we're not at the first child and are mid-scroll, make sure we obey the offset
        targetScrollX -= mTitleOffset;
      }

      scrollTo(targetScrollX, 0);
    }
  }

  private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
    private int mScrollState;

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
      int tabStripChildCount = mTabStrip.getChildCount();
      if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
        return;
      }

      mTabStrip.onViewPagerPageChanged(position, positionOffset);

      View selectedTitle = mTabStrip.getChildAt(position);
      int extraOffset = (selectedTitle != null)
          ? (int) (positionOffset * selectedTitle.getWidth())
          : 0;
      scrollToTab(position, extraOffset);

      if (mViewPagerPageChangeListener != null) {
        mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
            positionOffsetPixels);
      }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
      mScrollState = state;

      if (mViewPagerPageChangeListener != null) {
        mViewPagerPageChangeListener.onPageScrollStateChanged(state);
      }
    }

    @Override
    public void onPageSelected(int position) {
      if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
        mTabStrip.onViewPagerPageChanged(position, 0f);
        scrollToTab(position, 0);
      }

      updateTabsTextColor();

      if (mViewPagerPageChangeListener != null) {
        mViewPagerPageChangeListener.onPageSelected(position);
      }
    }

  }

  private void updateTabsTextColor() {
    final int selected = mViewPager.getCurrentItem();
    final int children = mTabStrip.getChildCount();
    for (int i = 0; i < children; i++) {
      final View view = mTabStrip.getChildAt(i);
      if (view instanceof TextView) {
        ((TextView) view).setTextColor(i == selected ?
            mSelectedTabColor : mUnselectedTabColor);
      }
    }
  }

  private class TabClickListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
      for (int i = 0; i < mTabStrip.getChildCount(); i++) {
        if (v == mTabStrip.getChildAt(i)) {
          mViewPager.setCurrentItem(i);
          return;
        }
      }
    }
  }

}
