package com.atr.tedit.mainstate;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcelable;
//import android.support.constraint.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
//import android.support.constraint.ConstraintSet;
import androidx.constraintlayout.widget.ConstraintSet;
//import android.support.v7.view.ContextThemeWrapper;
import androidx.appcompat.view.ContextThemeWrapper;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.AnticipateInterpolator;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.atr.tedit.R;
import com.atr.tedit.TEditActivity;
import com.atr.tedit.dialog.ConfirmCloseText;
import com.atr.tedit.dialog.ErrorMessage;
import com.atr.tedit.dialog.HelpDialog;
import com.atr.tedit.dialog.Sidebar;
import com.atr.tedit.file.descriptor.AndFile;
import com.atr.tedit.settings.Settings;
import com.atr.tedit.settings.TxtSettings;
import com.atr.tedit.util.FontUtil;
import com.atr.tedit.util.SettingsApplicable;
import com.atr.tedit.util.TEditDB;

/**
 * @author Adam T. Ryder
 * <a href="https://www.inventati.org/1337gallery">https://www.inventati.org/1337gallery</a>
 */

public class TabsWindow extends Sidebar implements SettingsApplicable {
    private final ListView tabsList;

    public TabsWindow(TEditActivity context) { 
        super(context, Sidebar.DIR_TO_RIGHT, R.layout.sidebar_tabs, R.id.tabsRoot);

        tabsList = sidebar.findViewById(R.id.tabsList);
        
        int fontSize = 16;
        int colorLightRust = ctx.getThemeColor(R.color.lightRust);

        Button helpButton = container.findViewById(R.id.helpButton);
        Button closeButton = container.findViewById(R.id.closeButton);

        ConstraintLayout csLayout = (ConstraintLayout)helpButton.getParent();
        ConstraintSet cset = new ConstraintSet();
        cset.clone(csLayout);

        csLayout.removeView(closeButton);
        closeButton = new Button(new ContextThemeWrapper(ctx, R.style.buttonFlatDarkRust));
        closeButton.setId(R.id.closeButton);
        closeButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize);
        closeButton.setText(ctx.getText(R.string.close));
        closeButton.setTextColor(colorLightRust);
        csLayout.addView(closeButton);

        csLayout.removeView(helpButton);
        helpButton = new Button(new ContextThemeWrapper(ctx, R.style.buttonFlatDarkRust));
        helpButton.setId(R.id.helpButton);
        helpButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize);
        helpButton.setText(ctx.getText(R.string.help));
        helpButton.setTextColor(colorLightRust);
        csLayout.addView(helpButton);

        cset.applyTo(csLayout);

        helpButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                HelpDialog hd = HelpDialog.newInstance(R.layout.help_tabs, ctx.getString(R.string.tabs));
                hd.show(ctx.getSupportFragmentManager(), "HelpDialog");
            }
        });
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (canClose())
                    close(true);
            }
        });

        tabsList.setOnItemClickListener(new ListView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView listView, View view, int position, long id) {
                if (!ctx.dbIsOpen()) {
                    ErrorMessage em = ErrorMessage.getInstance(ctx.getString(R.string.alert),
                            ctx.getString(R.string.error_dbclosed));
                    em.show(ctx.getSupportFragmentManager(), "dialog");
                    return;
                }

                DBItem item = (DBItem)listView.getItemAtPosition(position);
                if (ctx.getState() == ctx.STATE_TEXT && item.key == ((Editor)ctx.getFrag()).getKey())
                    return;

                Cursor cursor = ctx.getDB().fetchText(item.key);
                if (cursor == null) {
                    ErrorMessage em = ErrorMessage.getInstance(ctx.getString(R.string.alert),
                            ctx.getString(R.string.error_dberror));
                    em.show(ctx.getSupportFragmentManager(), "dialog");
                    populateTabs(false);
                    return;
                }
                cursor.close();

                ctx.openDocument(item.key);
            }
        });

        FontUtil.applyFont(FontUtil.getSystemTypeface(), container);
    }

    public ListView getListView() {
        return tabsList;
    }

    @Override
    public void open(boolean animate) {
		if (ctx.getFrag() instanceof Editor) {
			Editor editor = (Editor)ctx.getFrag();
			ctx.getDB().updateTextState(editor.getKey(), editor.getSettings());
		}
        populateTabs(true);
        tabsList.setEnabled(false);
        super.open(animate);

        handler.postDelayed(new Runnable() {
            public void run() {
                tabsList.setEnabled(true);
            }
        }, ANIMLENGTH);
    }

    @Override
    public void close(boolean animate) {
        tabsList.setEnabled(false);
        super.close(animate);
    }

    private void populateTabs(boolean animate) {
        Cursor cursor = ctx.getDB().fetchAllTextPreviews();
        if (cursor == null || cursor.getCount() == 0) {
            if (cursor != null)
                cursor.close();
            tabsList.setAdapter(new DBAdapter(ctx, (Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                    R.layout.tab_row : R.layout.tab_row_rtl, new DBItem[0], this));
            return;
        }

        DBItem[] items = new DBItem[cursor.getCount()];
        int index = 0;
        while (cursor.moveToNext()) {
            String name = null;
            long key = -1;
            String desc = "";
            if (cursor.getColumnIndexOrThrow(TEditDB.KEY_PATH) != -1) {
                String strName = cursor.getString(cursor.getColumnIndexOrThrow(TEditDB.KEY_PATH));
                if (strName.equalsIgnoreCase(TEditActivity.DEFAULTPATH)) {
                    name = TEditActivity.DEFAULTPATH;
                } else {
                    AndFile file = AndFile.createDescriptor(cursor.getString(cursor.getColumnIndexOrThrow(TEditDB.KEY_PATH)), ctx);
                    name = file == null ? null : file.getName();
                }
                key = cursor.getLong(cursor.getColumnIndexOrThrow(TEditDB.KEY_ROWID));
                desc = cursor.getString(cursor.getColumnIndexOrThrow(TEditDB.KEY_PREVIEW));
            }

            if (key == -1 || name == null)
                continue;

            items[index++] = new DBItem(name, key, desc);
        }
        cursor.close();

        DBAdapter adapter = new DBAdapter(ctx, (Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                R.layout.tab_row : R.layout.tab_row_rtl, items, this);
        if (tabsList.getAdapter() == null) {
            tabsList.setAdapter(adapter);
        } else {
            Parcelable state = tabsList.onSaveInstanceState();
            tabsList.setAdapter(adapter);
            tabsList.onRestoreInstanceState(state);
        }

        if (!animate || items.length == 0)
            return;

        tabsList.post(new Runnable() {
            @Override
            public void run() {
                int offset = 0;

                for (int i = 0; i < tabsList.getChildCount(); i++) {
                    final View view = getListView().getChildAt(i);
                    view.setAlpha(0);
                    Animation anim = AnimationUtils.loadAnimation(ctx, R.anim.tab_in);
                    anim.setStartOffset(offset);

                    anim.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {
                            view.setAlpha(1);
                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {

                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {

                        }
                    });

                    view.startAnimation(anim);
                    offset += 30;
                }
            }
        });
    }

    public void reset() {
        Cursor cursor = ctx.getDB().fetchAllTextPreviews();
        if (cursor == null) {
            tabsList.setAdapter(new DBAdapter(ctx, (Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                    R.layout.tab_row : R.layout.tab_row_rtl, new DBItem[0], this));
            return;
        }

        if (cursor.getCount() <= 0) {
            cursor.close();
            tabsList.setAdapter(new DBAdapter(ctx, (Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                    R.layout.tab_row : R.layout.tab_row_rtl, new DBItem[0], this));
            return;
        }
        cursor.close();
        populateTabs(false);
    }

    private void closeTab(long key) {
        if (!ctx.dbIsOpen())
            return;

        Cursor cursor = ctx.getDB().fetchText(key);
        if (cursor.getColumnIndexOrThrow(TEditDB.KEY_DATA) != -1) {
            TxtSettings settings = new TxtSettings(cursor.getBlob(cursor.getColumnIndexOrThrow(TEditDB.KEY_DATA)));
            cursor.close();
            if (!settings.saved) {
                ConfirmCloseText cct = ConfirmCloseText.getInstance(key);
                cct.show(ctx.getSupportFragmentManager(), "Confirm Close Text");
                return;
            }
        } else
            cursor.close();

        if (ctx.getState() == ctx.STATE_TEXT && ((Editor)ctx.getFrag()).getKey() == key) {
            if (!((Editor)ctx.getFrag()).getSettings().saved) {
                ConfirmCloseText cct = ConfirmCloseText.getInstance(key);
                cct.show(ctx.getSupportFragmentManager(), "Confirm Close Text");
                return;
            }
            ctx.closeText(key);
            tabsList.setEnabled(false);
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    tabsList.setEnabled(true);
                }
            }, ctx.SWAP_ANIM_LENGTH);
        } else
            ctx.getDB().deleteText(key);

        cursor = ctx.getDB().fetchAllTextPreviews();
        if (cursor == null) {
            tabsList.setAdapter(new DBAdapter(ctx, (Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                    R.layout.tab_row : R.layout.tab_row_rtl, new DBItem[0], this));
            return;
        } else if (cursor.getCount() <= 0) {
            cursor.close();
            tabsList.setAdapter(new DBAdapter(ctx, (Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                    R.layout.tab_row : R.layout.tab_row_rtl, new DBItem[0], this));
        } else {
            cursor.close();
            populateTabs(false);
        }
    }

    @Override
    public void setState(Bundle savedInstanceState) {
        super.setState(savedInstanceState);
        populateTabs(false);
    }

    @Override
    public void saveState(Bundle outState) {
    }

    private class DBItem {
        public final String name;
        public final long key;
        public final String desc;

        private DBItem(String name, long key, String description) {
            this.name = name;
            this.key = key;
            desc = description;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    @Override
    public void applySettings() {
        FontUtil.applyFont(FontUtil.getSystemTypeface(), container);
    }

    private static class DBAdapter extends ArrayAdapter<DBItem> {
        private final int layoutResID;
        private final int threshold;
        private final TabsWindow tabs;
        private final GestureDetector gesture;

        public DBAdapter(Context context, int layoutResID, DBItem[] items,
                         TabsWindow tabs) {
            super(context, layoutResID, items);
            gesture = new GestureDetector(context, new DBAdapter.SingleTapConfirm());
            this.tabs = tabs;
            this.layoutResID = layoutResID;
            threshold = Math.round(((TEditActivity)context).getMetrics().density * 24);
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            DBAdapter.ItemHolder holder = null;
            if (row == null) {
                LayoutInflater inflater = ((Activity)getContext()).getLayoutInflater();
                row = inflater.inflate(layoutResID, parent, false);
                holder = new DBAdapter.ItemHolder();

                holder.ll = (LinearLayout)row.findViewById(R.id.tablayout);
                holder.filename = (TextView)row.findViewById(R.id.tabfilename);
                holder.filename.setTypeface(FontUtil.getDefault());
                holder.description = (TextView)row.findViewById(R.id.tabdescription);
                holder.description.setTypeface(FontUtil.getEditorTypeface());

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                    holder.filename.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
                    holder.filename.setTextDirection((Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                            View.TEXT_DIRECTION_LTR : View.TEXT_DIRECTION_RTL);
                    holder.description.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
                    holder.description.setTextDirection((Settings.getSystemTextDirection() == Settings.TEXTDIR_LTR) ?
                            View.TEXT_DIRECTION_LTR : View.TEXT_DIRECTION_RTL);
                }

                row.setTag(holder);
                row.setOnTouchListener(touch);
            } else {
                holder = (DBAdapter.ItemHolder)convertView.getTag();
            }

            DBItem item = getItem(position);
            holder.filename.setText(item.name);
            holder.description.setText(item.desc);

            return row;
        }

        private View.OnTouchListener touch = new View.OnTouchListener() {
            private int initX = 0;
            private final float slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
            private boolean deleted = false;
            private long startTme;

            @Override
            public boolean onTouch(final View view, MotionEvent event) {
                if (gesture.onTouchEvent(event)) {
                    int pos = tabs.getListView().getPositionForView(view);
                    tabs.getListView().getOnItemClickListener().onItemClick(tabs.getListView(), view, pos,
                            tabs.getListView().getItemIdAtPosition(pos));
                    return true;
                }

                DBAdapter.ItemHolder holder = (DBAdapter.ItemHolder)view.getTag();

                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    if (deleted)
                        return true;

                    initX = (int)event.getX();
                    startTme = System.currentTimeMillis();
                    holder.ll.setTranslationX(0);
                } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                    if (deleted)
                        return true;

                    int offset = (int)(event.getX() - initX);
                    if (offset < -slop) {
                        holder.ll.setTranslationX(offset);
                        if (offset < -threshold) {
                            deleted = true;
                            int pos = tabs.getListView().getPositionForView(view);
                            final long key = ((DBItem)tabs.getListView().getItemAtPosition(pos)).key;

                            long tmeDiff = System.currentTimeMillis() - startTme;
                            int remaining = view.getWidth() - Math.abs(offset);
                            tmeDiff = Math.round(tmeDiff * (remaining / (float)Math.abs(offset)));
                            if (tmeDiff <= 0) {
                                tabs.closeTab(key);
                                return true;
                            }
                            tmeDiff = tmeDiff > 300 ? 300 : tmeDiff;

                            holder.ll.animate().setInterpolator(new AccelerateInterpolator())
                                    .translationX(offset >= 0 ? view.getWidth() : -view.getWidth())
                                    .setDuration(tmeDiff);
                            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    tabs.closeTab(key);
                                }
                            }, tmeDiff);
                        }
                    }
                } else if (event.getAction() == MotionEvent.ACTION_UP
                        || event.getAction() == MotionEvent.ACTION_CANCEL) {
                    if (!deleted) {
                        holder.ll.animate().setInterpolator(new AnticipateInterpolator()).translationX(0)
                                .setDuration(300);
                    }

                    if (event.getAction() == MotionEvent.ACTION_CANCEL)
                        return false;
                }

                return true;
            }
        };

        private static class SingleTapConfirm extends GestureDetector.SimpleOnGestureListener {

            @Override
            public boolean onSingleTapUp(MotionEvent event) {
                return true;
            }
        }

        private static class ItemHolder {
            public LinearLayout ll;
            public TextView filename;
            public TextView description;
        }
    }
}
