package org.geuz.onelab;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.app.Dialog;
import android.app.AlertDialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ParameterNumber extends Parameter {
    private double _value, _tmpValue, _min, _max, _step;
    private SeekBar _bar;
    private ArrayList<Double> _values;
    private ArrayList<String> _choices;
    private ArrayAdapter<String> _adapter;
    private Spinner _spinner;
    private CheckBox _checkbox;
    private EditText _edittext;
    private Stepper _stepper;

    public ParameterNumber(Context context, Gmsh gmsh, String name)
    {
        super(context, gmsh, name);
    }
    public ParameterNumber(Context context, Gmsh gmsh, String name,
                           double value, double min, double max, double step)
    {
        this(context, gmsh, name);
        _value = value;
        _min = min;
        _max = max;
        _step = step;
    }
    public ParameterNumber(Context context, Gmsh gmsh, String name, boolean readOnly,
                           double value, double min, double max, double step)
    {
        this(context, gmsh, name, value, min, max, step);
        _readOnly = readOnly;
    }

    public static String formatDouble(double x)
    {
        return String.format("%.6g", x).replaceFirst("\\.?0+(e|$)", "$1");
    }

    protected void update()
    {
        super.update();
        if(_bar != null) {
            _title.setText(getShortName() + " (" + formatDouble(_value) + ")");
            _bar.setMax(100);
            _bar.setProgress((int)(100*(_value-_min)/(_max-_min)));
            _bar.setEnabled(!this.isReadOnly());
        }
        else if(_spinner != null) {
            for(int i = 0; i < _choices.size(); i++)
                if(_values.get(i) == _value)
                    _spinner.setSelection(i, true);
        }
        else if(_checkbox != null) {
            _checkbox.setText(getShortName());
            _checkbox.setChecked((_value == 0)? false : true);
        }
        else if(_edittext != null) {
            _edittext.setText("" + formatDouble(_value));
        }
        else if(_stepper != null) {
            _stepper.setMaximum((int)Math.round(_max));
            _stepper.setMinimum((int)Math.round(_min));
            _stepper.setValue((int)Math.round(_value));
        }
    }
    public void setValue(double value)
    {
        if(value == _value) return;
        _value = value;
        _changed = true;
        _gmsh.setParam(getType(), getName(), String.valueOf(value));
        if(mListener != null) mListener.OnParameterChanged();
    }
    public void setMin(double min) { _min = min; this.update(); }
    public void setMax(double max) { _max = max; this.update(); }
    public void setStep(double step) { _step = step;this.update(); }
    public void addChoice(double choice, String value)
    {
        if(_values == null) {
            _values = new ArrayList<Double>();
            _choices = new ArrayList<String>();
            _values.add(choice);
            _choices.add(value);
            if(_spinner == null) {
                _spinner = new Spinner(_context);
                _adapter = new ArrayAdapter<String>(_context,
                                                    android.R.layout.simple_spinner_dropdown_item,
                                                    _choices);
                _adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                _spinner.setAdapter(_adapter);
            }
        }
        else{
            for(int i=0;i<_values.size();i++) {
                if(_values.get(i).equals(choice) && _choices.size() > i) {
                    _choices.set(i, value);
                    return;
                }
                else if(_values.get(i).equals(choice)){
                    _choices.add(value);
                    return;
                }
            }
            _values.add(choice);
            _choices.add(value);
        }
    }
    public double getValue() { return _value; }
    public double getMax() { return _max; }
    public double getMin() { return _min; }
    public double getStep() { return _step; }
    public int fromString(String s)
    {
        int pos = super.fromString(s);
        if(pos <= 0) return -1; // error
        String[] infos = s.split(Character.toString((char)0x03));
        String tmpVal = infos[pos++];
        if(tmpVal.equals("Inf")) // TODO set value to max ???
            _value = 1;
        else
            _value = Double.parseDouble(tmpVal);
        this.setMin(Double.parseDouble(infos[pos++]));
        this.setMax(Double.parseDouble(infos[pos++]));
        this.setStep(Double.parseDouble(infos[pos++]));
        pos++;// index
        int nChoix = Integer.parseInt(infos[pos++]); // choices' size
        double choices[] = new double[nChoix];
        for(int i = 0; i < nChoix; i++)
            choices[i] = Double.parseDouble(infos[pos++]); // choice
        int nLabels = Integer.parseInt(infos[pos++]); // labels' size
        if(nChoix == 2 && choices[0] == 0 && choices[1] == 1 && nLabels == 0) {
            _checkbox = new CheckBox(_context);
            this.update();
            return pos;
        }
        if(_choices != null)_choices.clear();
        if(_values != null) _values.clear();
        for(int i = 0; i < nLabels && nChoix == nLabels; i++){
            double val = Double.parseDouble(infos[pos++]); // choice
            this.addChoice(val, infos[pos++]); // label
        }
        // ...
        if(nLabels < 1 && _step == 0)
            _edittext = new EditText(_context);
        else if(_step == 1)
            _stepper = new Stepper(_context);
        else if(nLabels < 1)
            _bar = new SeekBar(_context);
        this.update();
        return pos;
    }
    public String getType(){return "ParameterNumber";}
    public LinearLayout getView()
    {
        LinearLayout paramLayout = new LinearLayout(_context);
        paramLayout.setOrientation(LinearLayout.VERTICAL);
        paramLayout.addView(_title);
        if(!_readOnly) paramLayout.setOnLongClickListener(new View.OnLongClickListener(){
                @Override
                public boolean onLongClick(View v)
                {
                    AlertDialog.Builder builder = new AlertDialog.Builder(_context);
                    LinearLayout layout = new LinearLayout(_context);
                    layout.setOrientation(LinearLayout.VERTICAL);
                    TextView label = new TextView(_context);
                    label.setText("Edit value of \n" + _name);
                    EditText edit = new EditText(_context);
                    edit.setText(String.valueOf(_value));
                    edit.addTextChangedListener(new TextWatcher() {
                            public void onTextChanged(CharSequence s, int start, int before, int count) {
                                try {
                                    if(s.length() < 1)  _tmpValue = 1;
                                    _tmpValue = Double.parseDouble(s.toString());
                                }
                                catch(NumberFormatException e) {
                                    _tmpValue = 1;
                                }
                            }
                            // UNUSED Auto-generated method stub
                            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
                            // UNUSED Auto-generated method stub
                            public void afterTextChanged(Editable s) {}
                        });
                    edit.requestFocus();
                    //_context.getWindow().setSoftInputMode
                    //    (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
                    layout.addView(label);
                    layout.addView(edit);
                    builder.setView(layout)
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    setValue(_tmpValue);
                                }
                            })
                        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    // User cancelled the dialog
                                }
                            });
                    builder.create().show();
                    return true;
                }
            });
        if(_spinner != null) {
            paramLayout.addView(_spinner);
            _spinner.setEnabled(!_readOnly);
            _spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                    public void onNothingSelected(AdapterView<?> arg0) {}
                    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                        setValue(_values.get(pos));
                    }
                });
        }
        else if(_bar != null) {
            paramLayout.addView(_bar);
            _bar.setEnabled(!_readOnly);
            _bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    public void onStopTrackingTouch(SeekBar seekBar) {
                        setValue(getMin() + (getMax() - getMin())*seekBar.getProgress()/100);
                    }
                    public void onStartTrackingTouch(SeekBar seekBar) {}
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
                });
        }
        else if(_checkbox != null) {
            paramLayout.removeView(_title);
            paramLayout.addView(_checkbox);
            _checkbox.setEnabled(!_readOnly);
            _checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        setValue((isChecked)? 1 : 0);
                    }
                });
        }
        else if(_edittext != null){
            paramLayout.addView(_edittext);
            _edittext.setEnabled(!_readOnly);

            _edittext.setOnKeyListener(new View.OnKeyListener() {
                    public boolean onKey(View v, int keyCode, KeyEvent event) {
                        if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
                            InputMethodManager imm = (InputMethodManager)_context.getSystemService
                                (Context.INPUT_METHOD_SERVICE);
                            imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
                            setValue(_value);
                            _edittext.clearFocus();
                            return true;
                        }
                        if(keyCode > KeyEvent.KEYCODE_9 &&
                           keyCode != KeyEvent.KEYCODE_NUMPAD_DOT &&
                           (keyCode <KeyEvent.KEYCODE_NUMPAD_0 ||
                            keyCode >KeyEvent.KEYCODE_NUMPAD_9) &&
                           keyCode != KeyEvent.KEYCODE_DEL)
                            return true;
                        return false;
                    }
                });
            _edittext.addTextChangedListener(new TextWatcher() {
                    public void onTextChanged(CharSequence s, int start, int before, int count) {
                        try {
                            if(s.length() < 1) _value = 1;
                            else _value = Double.parseDouble(s.toString());
                        }
                        catch(NumberFormatException e){
                            _value = 1;
                            //_edittext.setText("");
                        }
                    }
                    // UNUSED Auto-generated method stub
                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
                    // UNUSED Auto-generated method stub
                    public void afterTextChanged(Editable s) {}
                });
        }
        else if(_stepper != null) {
            paramLayout.addView(_stepper);
            _stepper.setOnValueChangedListener(new Stepper.OnValueChangedListener() {
                    public void onValueChanged() {
                        setValue(_stepper.getValue());
                    }
                });
        }
        return paramLayout;
    }
    private OnParameterChangedListener mListener;
    public void setOnParameterChangedListener(OnParameterChangedListener listener)
    {
        mListener = listener;
    }
    public interface OnParameterChangedListener
    {
        void OnParameterChanged();
    }
}
