/**
 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
 * This file is part of CSipSimple.
 *
 *  CSipSimple is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  If you own a pjsip commercial license you can also redistribute it
 *  and/or modify it under the terms of the GNU Lesser General Public License
 *  as an android library.
 *
 *  CSipSimple is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with CSipSimple.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.csipsimple.ui.prefs;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.SimpleAdapter;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockListFragment;
import com.csipsimple.R;
import com.csipsimple.api.SipConfigManager;
import com.csipsimple.utils.Log;
import com.csipsimple.utils.PreferencesWrapper;
import com.csipsimple.widgets.DragnDropListView;
import com.csipsimple.widgets.DragnDropListView.DropListener;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CodecsFragment extends SherlockListFragment implements OnCheckedChangeListener {

    protected static final String THIS_FILE = "CodecsFragment";

    private static final String CODEC_NAME = "codec_name";
    private static final String CODEC_ID = "codec_id";
    private static final String CODEC_PRIORITY = "codec_priority";
    
    public static final String BAND_TYPE = "band_type";
    public static final String MEDIA_TYPE = "media_type";
    public static final int MEDIA_AUDIO = 0;
    public static final int MEDIA_VIDEO = 1;
    public static final int MENU_ITEM_ACTIVATE = Menu.FIRST + 1;

    private SimpleAdapter mAdapter;
    private List<Map<String, Object>> codecsList;

    private PreferencesWrapper prefsWrapper;
    
    // Type for codec bandwidth
    private String bandtype;
    // Type for media (audio/video)
    private Integer mediatype;

    private boolean useCodecsPerSpeed = true;
    

    private static final Map<String, String> NON_FREE_CODECS = new HashMap<String, String>();

    static {
    };

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        prefsWrapper = new PreferencesWrapper(getActivity());
        useCodecsPerSpeed  = SipConfigManager.getPreferenceBooleanValue(getActivity(), SipConfigManager.CODECS_PER_BANDWIDTH);
        initDatas();
        setHasOptionsMenu(true);

        
        
        // Adapter
        mAdapter = new SimpleAdapter(getActivity(), codecsList, R.layout.codecs_list_item, new String[] {
                CODEC_NAME,
                CODEC_NAME,
                CODEC_PRIORITY
        }, new int[] {
                R.id.line1,
                R.id.AccCheckBoxActive,
                R.id.entiere_line
        });

        mAdapter.setViewBinder(new ViewBinder() {
            @Override
            public boolean setViewValue(View view, Object data, String textRepresentation) {
                if (view.getId() == R.id.entiere_line) {
                    Log.d(THIS_FILE, "Entiere line is binded ");
                    TextView tv = (TextView) view.findViewById(R.id.line1);
                    ImageView grabber = (ImageView) view.findViewById(R.id.icon);
                    CompoundButton checker = (CompoundButton) view.findViewById(R.id.AccCheckBoxActive);
                    checker.setOnCheckedChangeListener(CodecsFragment.this);
                    if ((Short) data == 0) {
                        tv.setTextColor(Color.GRAY);
                        grabber.setVisibility(View.GONE);
                        checker.setChecked(false);
                    } else {
                        tv.setTextColor(Color.WHITE);
                        grabber.setVisibility(View.VISIBLE);
                        checker.setChecked(true);
                    }
                    return true;
                }else if(view.getId() == R.id.AccCheckBoxActive) {
                    view.setTag(data);
                    return true;
                }
                return false;
            }

        });

        setListAdapter(mAdapter);
        registerForContextMenu(getListView());
    }
    
    /**
     * Initialize datas list
     */
    private void initDatas() {
        if(codecsList == null) {
            codecsList = new ArrayList<Map<String, Object>>();
        }else {
            codecsList.clear();
        }
        

        bandtype = (String) getArguments().get(BAND_TYPE);
        mediatype = (Integer) getArguments().get(MEDIA_TYPE);
        
        String[] codecNames;
        if(mediatype == MEDIA_AUDIO) {
            codecNames = prefsWrapper.getCodecList();
        }else {
            codecNames = prefsWrapper.getVideoCodecList();
        }
        
        int current_prio = 130;
        for(String codecName : codecNames) {
            Log.d(THIS_FILE, "Fill codec "+codecName+" for "+bandtype);
            String[] codecParts = codecName.split("/");
            if(codecParts.length >=2 ) {
                HashMap<String, Object> codecInfo = new HashMap<String, Object>();
                codecInfo.put(CODEC_ID, codecName);
                if(mediatype == MEDIA_AUDIO) {
                    codecInfo.put(CODEC_NAME, codecParts[0]+" "+codecParts[1].substring(0, codecParts[1].length()-3)+" kHz");
                }else if(mediatype == MEDIA_VIDEO) {
                    codecInfo.put(CODEC_NAME, codecParts[0]);
                }
                codecInfo.put(CODEC_PRIORITY, prefsWrapper.getCodecPriority(codecName, bandtype, Integer.toString(current_prio)));
                codecsList.add(codecInfo);
                current_prio --;
                Log.d(THIS_FILE, "Found priority is "+codecInfo.get(CODEC_PRIORITY));
            }
            
        }
        
        Collections.sort(codecsList, codecsComparator);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.codecs_list, container, false);

        DragnDropListView listView = (DragnDropListView) v.findViewById(android.R.id.list);
        listView.setOnDropListener(new DropListener() {
            @Override
            public void drop(int from, int to) {
                
                @SuppressWarnings("unchecked")
                HashMap<String, Object> item = (HashMap<String, Object>) getListAdapter().getItem(from);
                
                Log.d(THIS_FILE, "Dropped "+item.get(CODEC_NAME)+" -> "+to);
                
                //Prevent disabled codecsList to be reordered
                if((Short) item.get(CODEC_PRIORITY) <= 0 ) {
                    return ;
                }
                
                codecsList.remove(from);
                codecsList.add(to, item);
                
                //Update priorities
                short currentPriority = 130;
                for(Map<String, Object> codec : codecsList) {
                    if((Short) codec.get(CODEC_PRIORITY) > 0) {
                        if(currentPriority != (Short) codec.get(CODEC_PRIORITY)) {
                            setCodecPriority((String)codec.get(CODEC_ID), currentPriority);
                            codec.put(CODEC_PRIORITY, currentPriority);
                        }
                        //Log.d(THIS_FILE, "Reorder : "+codec.toString());
                        currentPriority --;
                    }
                }
                
                
                //Log.d(THIS_FILE, "Data set "+codecsList.toString());
                mAdapter.notifyDataSetChanged();
            }
        });
        
        listView.setOnCreateContextMenuListener(this);
        return v;
    }
    
    private void setCodecPriority(String codecName, short priority) {
        if(useCodecsPerSpeed) {
            prefsWrapper.setCodecPriority(codecName, bandtype, Short.toString(priority));
        }else {
            prefsWrapper.setCodecPriority(codecName, SipConfigManager.CODEC_NB, Short.toString(priority));
            prefsWrapper.setCodecPriority(codecName, SipConfigManager.CODEC_WB, Short.toString(priority));
        }
    }
    

    @Override
    @SuppressWarnings("unchecked")
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        AdapterView.AdapterContextMenuInfo info;
        try {
             info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        } catch (ClassCastException e) {
            Log.e(THIS_FILE, "bad menuInfo", e);
            return;
        }

        HashMap<String, Object> codec = (HashMap<String, Object>) mAdapter.getItem(info.position);
        if (codec == null) {
            // If for some reason the requested item isn't available, do nothing
            return;
        }
        
        boolean isDisabled = ((Short)codec.get(CODEC_PRIORITY) == 0);
        menu.add(0, MENU_ITEM_ACTIVATE, 0, isDisabled ? R.string.activate : R.string.deactivate);
        
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info;
        try {
             info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        } catch (ClassCastException e) {
            Log.e(THIS_FILE, "bad menuInfo", e);
            return false;
        }
        
        HashMap<String, Object> codec = null;
        codec = (HashMap<String, Object>) mAdapter.getItem(info.position);
        
        if (codec == null) {
            // If for some reason the requested item isn't available, do nothing
            return false;
        }
        int selId = item.getItemId();
        if (selId == MENU_ITEM_ACTIVATE) {
            boolean isDisabled = ((Short) codec.get(CODEC_PRIORITY) == 0);
            userActivateCodec(codec, isDisabled);
            return true;
        }
        return false;
    }
    
    private void userActivateCodec(final Map<String, Object> codec, boolean activate) {
        
        String codecName = (String) codec.get(CODEC_ID);
        final short newPrio = activate ? (short) 1 : (short) 0;

        boolean isDisabled = ((Short) codec.get(CODEC_PRIORITY) == 0);
        if(isDisabled == !activate) {
            // Nothing to do, this codec is already enabled
            return;
        }
        
        if(NON_FREE_CODECS.containsKey(codecName) && activate) {

            final TextView message = new TextView(getActivity());
            final SpannableString s = new SpannableString(getString(R.string.this_codec_is_not_free) + NON_FREE_CODECS.get(codecName));
            Linkify.addLinks(s, Linkify.WEB_URLS);
            message.setText(s);
            message.setMovementMethod(LinkMovementMethod.getInstance());
            message.setPadding(10, 10, 10, 10);
              
            
            //Alert user that we will disable for all incoming calls as he want to quit
            new AlertDialog.Builder(getActivity())
                .setTitle(R.string.warning)
                .setView(message)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        setCodecActivated(codec, newPrio);
                    }
                })
                .setNegativeButton(R.string.cancel, null)
                .show();
        }else {
            setCodecActivated(codec, newPrio);
        }
    }
    
    /**
     * Internal method to activate codec priority
     * @param codec the codec to activate
     * @param newPrio the new priority of the codec (0 to disable)
     */
    private void setCodecActivated(Map<String, Object> codec, short newPrio) {
        setCodecPriority((String) codec.get(CODEC_ID), newPrio);
        codec.put(CODEC_PRIORITY, newPrio);
        Collections.sort(codecsList, codecsComparator);
        mAdapter.notifyDataSetChanged();
    }


    /**
     * Class to compare the codecs based on their priority
     */
    private final Comparator<Map<String, Object>> codecsComparator = new Comparator<Map<String, Object>>() {
        @Override
        public int compare(Map<String, Object> infos1, Map<String, Object> infos2) {
            if (infos1 != null && infos2 != null) {
                short c1 = (Short)infos1.get(CODEC_PRIORITY);
                short c2 = (Short)infos2.get(CODEC_PRIORITY);
                if (c1 > c2) {
                    return -1;
                }
                if (c1 < c2) {
                    return 1;
                }
            }

            return 0;
        }
    };


    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        String codecName = (String) buttonView.getTag();
        if(codecName != null) {
            HashMap<String, Object> codec = null;
            for( int i = 0; i < mAdapter.getCount(); i++) {
                @SuppressWarnings("unchecked")
                HashMap<String, Object> tCodec = (HashMap<String, Object>) mAdapter.getItem(i);
                if(codecName.equalsIgnoreCase( (String) tCodec.get(CODEC_NAME))) {
                    codec = tCodec;
                    break;
                }
            }
            if(codec != null) {
                userActivateCodec(codec, isChecked);
            }
        }
    }
}