/*
 * 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.
 */

package com.doplgangr.secrecy.adapters;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.ViewAnimator;

import com.doplgangr.secrecy.Config;
import com.doplgangr.secrecy.CustomApp;
import com.doplgangr.secrecy.events.ThumbLoadDoneEvent;
import com.doplgangr.secrecy.exceptions.SecrecyFileException;
import com.doplgangr.secrecy.filesystem.files.EncryptedFile;
import com.doplgangr.secrecy.utils.Util;
import com.liangei.choosertest.R;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import de.greenrobot.event.EventBus;

public class FilesListAdapter extends RecyclerView.Adapter<FilesListAdapter.ViewHolder> {

    private final Context context;
    private boolean isGallery;
    private final int layout;
    // store (a reference to) the data
    private final List<EncryptedFile> data = new ArrayList<EncryptedFile>();
    private final Set<Integer> selectedItems = new HashSet<Integer>();
    private OnItemClickListener onItemClickListener;
    private OnItemLongClickListener onLongClickListener;

    public FilesListAdapter(Context context, boolean isGallery) {
        this.isGallery = false;
        this.context = context;
        this.isGallery = isGallery;
        layout = isGallery ? R.layout.gallery_item : R.layout.file_item;
        if (!EventBus.getDefault().isRegistered(this))
            EventBus.getDefault().register(this);
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    public void setOnLongClickListener(OnItemLongClickListener onLongClickListener) {
        this.onLongClickListener = onLongClickListener;
    }

    /**
     * Add data to data set.
     */
    public void add(EncryptedFile encryptedFile) {
        if (encryptedFile == null)
            return;
        if (encryptedFile.getDecryptedFileName() == null)
            return;
        if (isGallery) {
            String mimeType = Util.getFileTypeFromExtension(encryptedFile.getFileExtension());
            if (mimeType != null)
                if (!mimeType.contains("image"))
                    return;
        }
        if (!data.contains(encryptedFile)) {
            data.add(encryptedFile);
        }
        notifyItemInserted(data.size() - 1);
    }

    public void remove(int position) {
        data.remove(position);
        notifyItemRemoved(position);
    }

    public void remove(List<Integer> selected) {
        // Remove items in reverse order to keep indices in order
        Collections.sort(selected, Collections.reverseOrder());
        for (Integer i : selected) {
            data.remove((int) i);
            notifyItemRemoved(i);
        }
    }

    /**
     * Return the size of the data set.
     */
    @Override
    public int getItemCount() {
        return this.data.size();
    }

    /**
     * Return if index is in data set.
     */
    public boolean hasIndex(int position) {
        return this.data.size() > position && position > -1;
    }

    /**
     * Return an object in the data set.
     */
    public EncryptedFile getItem(int position) {
        return this.data.get(position);
    }

    /**
     * Return the position provided.
     */
    public int getItemId(EncryptedFile encryptedFile) {
        return data.indexOf(encryptedFile);
    }

    public void onEventMainThread(ThumbLoadDoneEvent event) {
        try {
            String name = (String) event.imageView.getTag();
            if (name.equals(event.encryptedFile.getDecryptedFileName()) && (event.bitmap != null) && (event.imageView != null)) {
                event.imageView.setImageBitmap(event.bitmap);   // bind thumbnail in UI thread
                event.imageView.setVisibility(View.VISIBLE);
            }
        } catch (OutOfMemoryError ignored) {
        }
    }

    boolean isSelected(int position){
        return selectedItems.contains(position);
    }

    public boolean select(int position) {
        if (isSelected(position)){
            selectedItems.remove(position);
            return false;
        }
        selectedItems.add(position);
        return true;
    }

    public Set<Integer> getSelected() {
        return selectedItems;
    }

    public void clearSelected() {
        selectedItems.clear();
        notifyDataSetChanged();
    }

    public void clear() {
        data.clear();
        selectedItems.clear();
    }

    public void sort() {
        Comparator<EncryptedFile> comparator;

        switch (PreferenceManager.getDefaultSharedPreferences(context).getString(
                Config.VAULT_SORT, Config.VAULT_SORT_ALPHABETIC)) {

            case Config.VAULT_SORT_ALPHABETIC:
                comparator = Config.COMPARATOR_ENCRYPTEDFILE_ALPHABETIC;
                break;
            case Config.VAULT_SORT_FILETYPE:
                comparator = Config.COMPARATOR_ENCRYPTEDFILE_FILETYPE;
                break;
            case Config.VAULT_SORT_LASTMODIFIED:
                comparator = Config.COMPARATOR_ENCRYPTEDFILE_LASTMODIFIED;
                break;
            default:
                comparator = null;
        }

        if (comparator != null) {
            Collections.sort(data, comparator);
            notifyDataSetChanged();
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(layout, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final ViewHolder viewHolder, int position) {
        final EncryptedFile encryptedFile = this.data.get(position);

        if (viewHolder.name != null){
            viewHolder.name.setText(encryptedFile.getDecryptedFileName());
        }
        if (viewHolder.type != null) {
            viewHolder.type.setText(encryptedFile.getType());
        }
        if (viewHolder.size != null) {
            viewHolder.size.setText(encryptedFile.getFileSize());
        }
        if (viewHolder.date != null) {
            viewHolder.date.setText(encryptedFile.getTimestamp());
        }
        if (viewHolder.thumbnail != null) {
            viewHolder.thumbnail.setVisibility(View.GONE);
            viewHolder.thumbnail.setTag(encryptedFile.getDecryptedFileName());
        }
        if (viewHolder.frame != null) {
            viewHolder.frame.setForeground(isSelected(position) ?
                            context.getResources().getDrawable(R.drawable.file_selector) :
                            null);
        }

        if (viewHolder.progressBar != null){
            encryptedFile.setProgressBar(viewHolder.progressBar);
            encryptedFile.getProgressBar().setMax((int) encryptedFile.getFile().length());
        }

        if (viewHolder.animator != null) {
            viewHolder.animator.setDisplayedChild(viewHolder.page);

            int viewIndex;
            if (data.get(position).getIsDecrypting()){
                viewIndex = 1;
            } else {
                viewHolder.animator.setInAnimation(null);
                viewIndex = 0;
            }
            viewHolder.animator.setDisplayedChild(viewIndex);
        }

        final int avatar_size = (int) CustomApp.context.getResources().getDimension(R.dimen.list_item_avatar_size);

        // This class is for binding thumbnail to UI
        class BindImageTask extends AsyncTask<EncryptedFile, Void, Bitmap> {
            protected Bitmap doInBackground(EncryptedFile... files) {
                if (isGallery) {
                    try {
                        return files[0].getEncryptedThumbnail().getThumb(100);
                    } catch (SecrecyFileException e) {
                        Util.log("No bitmap available!");
                    }
                }
                try {
                    return files[0].getEncryptedThumbnail().getThumb(avatar_size);     // async decrypt thumbnail
                } catch (SecrecyFileException e) {
                    Util.log("No bitmap available!");
                }
                return null;
            }

            protected void onPostExecute(Bitmap thumbnail) {
                String name = (String) viewHolder.thumbnail.getTag();
                if (name.equals(encryptedFile.getDecryptedFileName()) && (thumbnail != null) && (viewHolder.thumbnail != null)) {
                    viewHolder.thumbnail.setImageBitmap(thumbnail);   // bind thumbnail in UI thread
                    viewHolder.thumbnail.setVisibility(View.VISIBLE);
                }
            }
        }
        new BindImageTask().execute(encryptedFile);
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

        public final TextView name;
        public final TextView type;
        public final TextView size;
        public final TextView date;
        public final ImageView thumbnail;
        public final FrameLayout frame;
        public final ViewAnimator animator;
        public final ProgressBar progressBar;
        public int page;

        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.name);
            type = (TextView) itemView.findViewById(R.id.type);
            size = (TextView) itemView.findViewById(R.id.size);
            date = (TextView) itemView.findViewById(R.id.date);
            thumbnail = (ImageView) itemView.findViewById(R.id.thumbNail);
            frame = (FrameLayout) itemView.findViewById(R.id.frame);
            frame.setTag(this);
            animator = (ViewAnimator) itemView.findViewById(R.id.viewAnimator);
            progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar);
            frame.setOnClickListener(this);
            frame.setOnLongClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (onItemClickListener != null) {
                onItemClickListener.onItemClick(view, getPosition());
            }
        }

        @Override
        public boolean onLongClick(View view) {
            if (onLongClickListener != null){
                onLongClickListener.onItemLongClick(view, getPosition());
                return true;
            }
            return false;
        }
    }

    public interface OnItemClickListener {
        public void onItemClick(View view, int position);
    }
    public interface OnItemLongClickListener {
        public boolean onItemLongClick(View view, int position);
    }

}
