public class ConverterFragment extends Fragment {
    private int converterSpinnerPosition;

    public ConverterFragment() {
    }

    public static android.support.v4.app.Fragment newInstance() {
        return new ConverterFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_converter, container, false);
        return root;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        final Spinner unitSpinner = (Spinner) view.findViewById(R.id.units_spinner);
        String[] unitsArray = {"Area", "Cooking", "Digital Storage", "Energy", "Fuel Consumption",
                "Length / Distance", "Mass / Weight", "Power", "Pressure", "Speed",
                "Time", "Torque", "Volume"};
        final Spinner from = (Spinner) view.findViewById(R.id.from_spinner);
        final Spinner to = (Spinner) view.findViewById(R.id.to_spinner);

        final SharedPreferences preferences = getActivity().getSharedPreferences("pref_name", Context.MODE_PRIVATE);
        final String[] areaHeaders = {getResources().getString(R.string.sq_kilometre),
                getResources().getString(R.string.sq_metre),
                getResources().getString(R.string.sq_centimetre),
                getResources().getString(R.string.hectare),
                getResources().getString(R.string.sq_mile),
                getResources().getString(R.string.sq_yard),
                getResources().getString(R.string.sq_foot),
                getResources().getString(R.string.sq_inch),
                getResources().getString(R.string.acre)};

        final String[] cookingHeaders = {getResources().getString(R.string.teaspoon),
                getResources().getString(R.string.tablespoon),
                getResources().getString(R.string.cup),
                getResources().getString(R.string.fluid_ounce),
                getResources().getString(R.string.fluid_ounce_uk),
                getResources().getString(R.string.pint),
                getResources().getString(R.string.pint_uk),
                getResources().getString(R.string.quart),
                getResources().getString(R.string.quart_uk),
                getResources().getString(R.string.gallon),
                getResources().getString(R.string.gallon_uk),
                getResources().getString(R.string.millilitre),
                getResources().getString(R.string.litre)};

        final String[] digitalHeaders = {getResources().getString(R.string.bit),
                getResources().getString(R.string.Byte),
                getResources().getString(R.string.kilobit),
                getResources().getString(R.string.kilobyte),
                getResources().getString(R.string.megabit),
                getResources().getString(R.string.megabyte),
                getResources().getString(R.string.gigabit),
                getResources().getString(R.string.gigabyte),
                getResources().getString(R.string.terabit),
                getResources().getString(R.string.terabyte)};

        final String[] energyHeaders = {getResources().getString(R.string.joule),
                getResources().getString(R.string.kilojoule),
                getResources().getString(R.string.calorie),
                getResources().getString(R.string.kilocalorie),
                getResources().getString(R.string.btu),
                getResources().getString(R.string.ft_lbF),
                getResources().getString(R.string.in_lbF),
                getResources().getString(R.string.kilowatt_hour),
                getResources().getString(R.string.electron_volt)};

        final String[] fuelHeaders = {getResources().getString(R.string.mpg_us),
                getResources().getString(R.string.mpg_uk),
                getResources().getString(R.string.l_100k),
                getResources().getString(R.string.km_l),
                getResources().getString(R.string.miles_l)};

        final String[] lengthHeaders = {getResources().getString(R.string.kilometre),
                getResources().getString(R.string.mile),
                getResources().getString(R.string.metre),
                getResources().getString(R.string.centimetre),
                getResources().getString(R.string.millimetre),
                getResources().getString(R.string.micrometre),
                getResources().getString(R.string.nanometre),
                getResources().getString(R.string.yard),
                getResources().getString(R.string.feet),
                getResources().getString(R.string.feet_inch),
                getResources().getString(R.string.inch),
                getResources().getString(R.string.nautical_mile),
                getResources().getString(R.string.furlong),
                getResources().getString(R.string.light_year)};

        final String[] massHeaders = {getResources().getString(R.string.kilogram),
                getResources().getString(R.string.pound),
                getResources().getString(R.string.gram),
                getResources().getString(R.string.milligram),
                getResources().getString(R.string.ounce),
                getResources().getString(R.string.grain),
                getResources().getString(R.string.stone),
                getResources().getString(R.string.metric_ton),
                getResources().getString(R.string.short_ton),
                getResources().getString(R.string.long_ton)};

        final String[] powerHeaders = {getResources().getString(R.string.watt),
                getResources().getString(R.string.kilowatt),
                getResources().getString(R.string.megawatt),
                getResources().getString(R.string.hp),
                getResources().getString(R.string.hp_uk),
                getResources().getString(R.string.ft_lbf_s),
                getResources().getString(R.string.calorie_s),
                getResources().getString(R.string.btu_s),
                getResources().getString(R.string.kva),
                getResources().getString(R.string.electron_volt)};

        final String[] pressureHeaders = {getResources().getString(R.string.megapascal),
                getResources().getString(R.string.kilopascal),
                getResources().getString(R.string.pascal),
                getResources().getString(R.string.bar),
                getResources().getString(R.string.psi),
                getResources().getString(R.string.psf),
                getResources().getString(R.string.atmosphere),
                getResources().getString(R.string.technical_atmosphere),
                getResources().getString(R.string.mmhg),
                getResources().getString(R.string.torr)};

        final String[] speedHeaders = {getResources().getString(R.string.km_h),
                getResources().getString(R.string.mph),
                getResources().getString(R.string.m_s),
                getResources().getString(R.string.fps),
                getResources().getString(R.string.knot)};

        final String[] timeHeaders = {getResources().getString(R.string.year),
                getResources().getString(R.string.month),
                getResources().getString(R.string.week),
                getResources().getString(R.string.day),
                getResources().getString(R.string.hour),
                getResources().getString(R.string.minute),
                getResources().getString(R.string.second),
                getResources().getString(R.string.millisecond),
                getResources().getString(R.string.nanosecond)};

        final String[] torqueHeaders = {getResources().getString(R.string.n_m),
                getResources().getString(R.string.ft_lbF),
                getResources().getString(R.string.in_lbF)};

        final String[] volumeHeaders = {getResources().getString(R.string.teaspoon),
                getResources().getString(R.string.tablespoon),
                getResources().getString(R.string.cup),
                getResources().getString(R.string.fluid_ounce),
                getResources().getString(R.string.fluid_ounce_uk),
                getResources().getString(R.string.pint),
                getResources().getString(R.string.pint_uk),
                getResources().getString(R.string.quart),
                getResources().getString(R.string.quart_uk),
                getResources().getString(R.string.gallon),
                getResources().getString(R.string.gallon_uk),
                getResources().getString(R.string.barrel),
                getResources().getString(R.string.barrel_uk),
                getResources().getString(R.string.millilitre),
                getResources().getString(R.string.litre),
                getResources().getString(R.string.cubic_cm),
                getResources().getString(R.string.cubic_m),
                getResources().getString(R.string.cubic_inch),
                getResources().getString(R.string.cubic_foot),
                getResources().getString(R.string.cubic_yard)};

        ArrayAdapter<String> adapterUnits = new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_spinner_item, unitsArray);
        adapterUnits.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        unitSpinner.setAdapter(adapterUnits);
        unitSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                unitSpinner.setSelection(position);
                converterSpinnerPosition = unitSpinner.getSelectedItemPosition();
                preferences.edit().putInt("converterSpinnerPosition", converterSpinnerPosition).apply();
                switch (position) {
                    case 0:
                        setUnitsAdapter(areaHeaders, from, to);
                        break;
                    case 1:
                        setUnitsAdapter(cookingHeaders, from, to);
                        break;
                    case 2:
                        setUnitsAdapter(digitalHeaders, from, to);
                        break;
                    case 3:
                        setUnitsAdapter(energyHeaders, from, to);
                        break;
                    case 4:
                        setUnitsAdapter(fuelHeaders, from, to);
                        break;
                    case 5:
                        setUnitsAdapter(lengthHeaders, from, to);
                        break;
                    case 6:
                        setUnitsAdapter(massHeaders, from, to);
                        break;
                    case 7:
                        setUnitsAdapter(powerHeaders, from, to);
                        break;
                    case 8:
                        setUnitsAdapter(pressureHeaders, from, to);
                        break;
                    case 9:
                        setUnitsAdapter(speedHeaders, from, to);
                        break;
                    case 10:
                        setUnitsAdapter(timeHeaders, from, to);
                        break;
                    case 11:
                        setUnitsAdapter(torqueHeaders, from, to);
                        break;
                    case 12:
                        setUnitsAdapter(volumeHeaders, from, to);
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
        unitSpinner.setSelection(preferences.getInt("converterSpinnerPosition", 0));
    }

    public void setUnitsAdapter(String[] headers, final Spinner from, final Spinner to) {
        ArrayAdapter<String> adapterUnits = new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_spinner_item, headers);
        adapterUnits.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        from.setAdapter(adapterUnits);
        to.setAdapter(adapterUnits);
    }
} public class CurrencyFragment extends Fragment {
    private AutoResizeTextView result_TV, resultant_TV;
    private Spinner fro, too;
    private Button convertBtn;
    private Double convertDouble;
    private int numFromCurrency;
    private int numToCurrency;
    String fromString;
    String toString;

    public CurrencyFragment() {
    }

    public static android.support.v4.app.Fragment newInstance() {
        return new CurrencyFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_currency, container, false);
        result_TV = (AutoResizeTextView) root.findViewById(R.id.curr_result_TV);
        resultant_TV = (AutoResizeTextView) root.findViewById(R.id.curr_resultant_TV);
        convertBtn = (Button) root.findViewById(R.id.equals_Btn);

        fro = (Spinner) root.findViewById(R.id.fro_spinner);
        too = (Spinner) root.findViewById(R.id.too_spinner);

        ArrayAdapter<String> froAdapter = new ArrayAdapter<>(getActivity(),
                R.layout.currency_spinner_item, getResources().getStringArray(R.array.currency_exp));
        froAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        fro.setAdapter(froAdapter);
        too.setAdapter(froAdapter);
        result_TV.setText("1");

        convertBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Crashlytics.getInstance().crash(); // Force a crash
                resultant_TV.setText(R.string.currency_process);
                String convertValue = result_TV.getText().toString();
                convertDouble = Double.parseDouble(convertValue);

                numFromCurrency = fro.getSelectedItemPosition();
                numToCurrency = too.getSelectedItemPosition();


                if (numFromCurrency != numToCurrency) {
                    String getFromString = getResources().getStringArray(R.array.currency_exp)[numFromCurrency].substring(0, 3);
                    String getToString = getResources().getStringArray(R.array.currency_exp)[numToCurrency].substring(0, 3);
                    ConversionRate conversionRate = new ConversionRate();
                    conversionRate.execute(getFromString, getToString);
                } else {
                    resultant_TV.setText("1");
                    SharedPreferences settings = getActivity().getSharedPreferences("MyPrefs", 0);
                    SharedPreferences.Editor editor = settings.edit();
                    editor.putFloat("rate", 1);
                    editor.apply();
                }
            }
        });


        fro.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                fromString = fro.getSelectedItem().toString();
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
        too.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                toString = too.getSelectedItem().toString();
                resultant_TV.setText(R.string.currency_process);
                String convertValue = result_TV.getText().toString();
                convertDouble = Double.parseDouble(convertValue);

                numFromCurrency = fro.getSelectedItemPosition();
                numToCurrency = too.getSelectedItemPosition();


                if (numFromCurrency != numToCurrency) {
                    String getFromString = getResources().getStringArray(R.array.currency_exp)[numFromCurrency].substring(0, 3);
                    String getToString = getResources().getStringArray(R.array.currency_exp)[numToCurrency].substring(0, 3);
                    ConversionRate conversionRate = new ConversionRate();
                    conversionRate.execute(getFromString, getToString);
                } else {
                    resultant_TV.setText("1");
                    SharedPreferences settings = getActivity().getSharedPreferences("MyPrefs", 0);
                    SharedPreferences.Editor editor = settings.edit();
                    editor.putFloat("rate", 1);
                    editor.apply();
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

        return root;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }

    private class ConversionRate extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... strings) {
            String fromString = strings[0];
            String toString = strings[1];

            String jsonUrl = "https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency="+fromString+"&to_currency="+toString+"&apikey=F3ON8QP7H4Z4K3Q1";

            try {
                URL jsonConnect = new URL(jsonUrl);
                HttpURLConnection httpURLConnection = (HttpURLConnection) jsonConnect.openConnection();
                httpURLConnection.setRequestMethod("GET");
                httpURLConnection.setDoInput(true);

                InputStream inputStream = httpURLConnection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
                String response = " ";
                String line = "";
                while ((line = reader.readLine()) != null) {
                    response += line;
                }
                reader.close();
                httpURLConnection.disconnect();
                inputStream.close();
                return response;
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException io) {
                Log.w("Caught Exception", io);
            }
            return null;
        }

        @Override
        protected  void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            try {
                JSONObject jsonObject = new JSONObject(s);
                String exResult = jsonObject.getJSONObject("Realtime Currency Exchange Rate").getString("5. Exchange Rate");
                double conversionDouble = Double.parseDouble(exResult);
                double conversion = conversionDouble * convertDouble;
                DecimalFormat df = new DecimalFormat();
                df.setMaximumFractionDigits(5);

                resultant_TV.setText(df.format(conversion));
            } catch (JSONException e) {
                e.printStackTrace();
            } catch (NullPointerException npe) {
                Toast.makeText(getContext(), "Sorry! You must be connected to the internet to convert", Toast.LENGTH_LONG).show();
                Crashlytics.logException(npe);
                resultant_TV.setText(R.string.currency_connection_error);
            } catch (NumberFormatException nfe) {
                Toast.makeText(getContext(), "Sorry! You must enter a number to convert", Toast.LENGTH_LONG).show();
            }
        }

        @Override
        protected void onPreExecute() {
            Toast toast = Toast.makeText(getActivity(), "Updating Exchange Rates", Toast.LENGTH_SHORT);
            toast.show();
            super.onPreExecute();
        }
    }
    @Override
    public void onPause(){
        super.onPause();
        SharedPreferences preferences = getActivity().getSharedPreferences("pref_name", Context.MODE_PRIVATE);
        preferences.edit().putInt("spinner_index", fro.getSelectedItemPosition()).apply();
        preferences.edit().putInt("spinner_indexes", too.getSelectedItemPosition()).apply();
    }
    @Override
    public void onResume(){
        super.onResume();
        SharedPreferences preferences = getActivity().getSharedPreferences("pref_name", Context.MODE_PRIVATE);
        int spinnerIndx = preferences.getInt("spinner_index", 0);
        int spinnerIndxes = preferences.getInt("spinner_indexes", 0);
        fro.setSelection(spinnerIndx);
        too.setSelection(spinnerIndxes);
    }
} public class DateFragment extends Fragment {

    public Calendar calendar;
    public TextView startDateView, endDateView, startTimeView, endTimeView;
    public int year_start, month_start, day_start, year_end, month_end, day_end;
    public int hour_start, minute_start, hour_end, minute_end;
    public boolean is24HourView;
    String stringStartDate, stringEndDate;
    Button startDateBtn, endDateBtn, startTimeBtn, endTimeBtn;
    private DatePickerDialog.OnDateSetListener myStartDateListener = new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker arg0, int arg1, int arg2, int arg3) {
            year_start = arg1;
            month_start = arg2 + 1;
            day_start = arg3;
            startDateView.setText(year_start + "-" + month_start + "-" + day_start);
        }
    };
    private DatePickerDialog.OnDateSetListener myEndDateListener = new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker arg0, int arg1, int arg2, int arg3) {
            year_end = arg1;
            month_end = arg2 + 1;
            day_end = arg3;
            endDateView.setText(year_end + "-" + month_end + "-" + day_end);
        }
    };
    private TimePickerDialog.OnTimeSetListener myStartTimeListener = new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker arg0, int arg1, int arg2) {
            hour_start = arg1;
            minute_start = arg2;
            startTimeView.setText(hour_start + ":" + minute_start);
        }
    };
    private TimePickerDialog.OnTimeSetListener myEndTimeListener = new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker arg0, int arg1, int arg2) {
            hour_end = arg1;
            minute_end = arg2;
            endTimeView.setText(hour_end + ":" + minute_end);
        }
    };

    public DateFragment() {
    }

    public static android.support.v4.app.Fragment newInstance() {
        return new DateFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_date, container, false);
    }

    @Override
    public void onViewCreated(final View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        startDateView = (TextView) view.findViewById(R.id.startDateTextView);
        calendar = Calendar.getInstance();

        year_start = calendar.get(Calendar.YEAR);
        month_start = calendar.get(Calendar.MONTH);
        day_start = calendar.get(Calendar.DAY_OF_MONTH);

        endDateView = (TextView) view.findViewById(R.id.endDateTextView);
        year_end = calendar.get(Calendar.YEAR);
        month_end = calendar.get(Calendar.MONTH);
        day_end = calendar.get(Calendar.DAY_OF_MONTH);

        startTimeView = (TextView) view.findViewById(R.id.startTimeTextView);
        endTimeView = (TextView) view.findViewById(R.id.endTimeTextView);

        startDateView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new DatePickerDialog(getActivity(), myStartDateListener, year_start, month_start, day_start);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });
        startDateBtn = (Button) view.findViewById(R.id.start_date_btn);
        startDateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new DatePickerDialog(getActivity(), myStartDateListener, year_start, month_start, day_start);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });

        endDateView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new DatePickerDialog(getActivity(), myEndDateListener, year_end, month_end, day_end);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });
        endDateBtn = (Button) view.findViewById(R.id.end_date_btn);
        endDateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new DatePickerDialog(getActivity(), myEndDateListener, year_end, month_end, day_end);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });

        startTimeView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new TimePickerDialog(getActivity(), myStartTimeListener, hour_start, minute_start, is24HourView);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });
        startTimeBtn = (Button) view.findViewById(R.id.start_time_btn);
        startTimeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new TimePickerDialog(getActivity(), myStartTimeListener, hour_start, minute_start, is24HourView);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });

        endTimeView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new TimePickerDialog(getActivity(), myEndTimeListener, hour_end, minute_end, is24HourView);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });
        endTimeBtn = (Button) view.findViewById(R.id.end_time_btn);
        endTimeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Dialog dialog = new TimePickerDialog(getActivity(), myEndTimeListener, hour_end, minute_end, is24HourView);
                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        calcDiff(view);
                    }
                });
                dialog.show();
            }
        });
    }

    public void calcDiff(View view) {
        try {
            stringStartDate = year_start + " " + month_start + " " + day_start + " " + hour_start + ":" + minute_start;
            stringEndDate = year_end + " " + month_end + " " + day_end + " " + hour_end + ":" + minute_end;
            DateFormat format = new SimpleDateFormat("yyyy MM d HH:mm", Locale.ENGLISH);
            Date startDate = format.parse(stringStartDate);
            Date endDate = format.parse(stringEndDate);
            System.out.println(startDate);
            System.out.println(endDate);
            long different = endDate.getTime() - startDate.getTime();

            long secondsInMilli = 1000;
            long minutesInMilli = secondsInMilli * 60;
            long hoursInMilli = minutesInMilli * 60;
            long daysInMilli = hoursInMilli * 24;

            long elapsedDays = different / daysInMilli;
            different = different % daysInMilli;

            long elapsedHours = different / hoursInMilli;
            different = different % hoursInMilli;

            long elapsedMinutes = different / minutesInMilli;
            different = different % minutesInMilli;

            long elapsedSeconds = different / secondsInMilli;

            TextView resultView = (TextView) view.findViewById(R.id.result);
            resultView.setText(elapsedDays + " days\n" + elapsedHours + " hours\n" + elapsedMinutes + " minutes\n");
        } catch (Exception e) {
            //
        }
    }
} public class UnitsFragment extends Fragment {
    private int unitSpinnerPosition;
    public UnitsFragment() {
    }

    public static android.support.v4.app.Fragment newInstance() {
        return new UnitsFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        return inflater.inflate(R.layout.fragment_units, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        final Spinner unitSpinner = (Spinner) view.findViewById(R.id.units_spinner);
        String[] unitsArray = {"Area", "Cooking", "Digital Storage", "Energy", "Fuel Consumption",
                "Length / Distance", "Mass / Weight", "Power", "Pressure", "Speed",
                "Time", "Torque", "Volume"};

        final SharedPreferences preferences = getActivity().getSharedPreferences("pref_name", Context.MODE_PRIVATE);
        final TextView[] headers = {(TextView) view.findViewById(R.id.unit_header1),
                (TextView) view.findViewById(R.id.unit_header2),
                (TextView) view.findViewById(R.id.unit_header3),
                (TextView) view.findViewById(R.id.unit_header4),
                (TextView) view.findViewById(R.id.unit_header5),
                (TextView) view.findViewById(R.id.unit_header6),
                (TextView) view.findViewById(R.id.unit_header7),
                (TextView) view.findViewById(R.id.unit_header8),
                (TextView) view.findViewById(R.id.unit_header9),
                (TextView) view.findViewById(R.id.unit_header10),
                (TextView) view.findViewById(R.id.unit_header11),
                (TextView) view.findViewById(R.id.unit_header12),
                (TextView) view.findViewById(R.id.unit_header13),
                (TextView) view.findViewById(R.id.unit_header14),
                (TextView) view.findViewById(R.id.unit_header15),
                (TextView) view.findViewById(R.id.unit_header16),
                (TextView) view.findViewById(R.id.unit_header17),
                (TextView) view.findViewById(R.id.unit_header18),
                (TextView) view.findViewById(R.id.unit_header19),
                (TextView) view.findViewById(R.id.unit_header20)};

        final EditText[] values = {(EditText) view.findViewById(R.id.unit_value1),
                (EditText) view.findViewById(R.id.unit_value2),
                (EditText) view.findViewById(R.id.unit_value3),
                (EditText) view.findViewById(R.id.unit_value4),
                (EditText) view.findViewById(R.id.unit_value5),
                (EditText) view.findViewById(R.id.unit_value6),
                (EditText) view.findViewById(R.id.unit_value7),
                (EditText) view.findViewById(R.id.unit_value8),
                (EditText) view.findViewById(R.id.unit_value9),
                (EditText) view.findViewById(R.id.unit_value10),
                (EditText) view.findViewById(R.id.unit_value11),
                (EditText) view.findViewById(R.id.unit_value12),
                (EditText) view.findViewById(R.id.unit_value13),
                (EditText) view.findViewById(R.id.unit_value14),
                (EditText) view.findViewById(R.id.unit_value15),
                (EditText) view.findViewById(R.id.unit_value16),
                (EditText) view.findViewById(R.id.unit_value17),
                (EditText) view.findViewById(R.id.unit_value18),
                (EditText) view.findViewById(R.id.unit_value19),
                (EditText) view.findViewById(R.id.unit_value20)};

        final String[] areaHeaders = {getResources().getString(R.string.sq_kilometre),
                getResources().getString(R.string.sq_metre),
                getResources().getString(R.string.sq_centimetre),
                getResources().getString(R.string.hectare),
                getResources().getString(R.string.sq_mile),
                getResources().getString(R.string.sq_yard),
                getResources().getString(R.string.sq_foot),
                getResources().getString(R.string.sq_inch),
                getResources().getString(R.string.acre)};

        final double[][] areaValues = {{1000000.0, 0.000001}, {1.0, 1.0}, {0.0001, 10000.0}, {10000.0, 0.0001},
                {2589988.110336, 0.000000386102158542445847}, {0.83612736, 1.19599004630108026},
                {0.09290304, 10.7639104167097223}, {0.00064516, 1550.00310000620001},
                {4046.8564224, 0.000247105381467165342}};

        final String[] cookingHeaders = {getResources().getString(R.string.teaspoon),
                getResources().getString(R.string.tablespoon),
                getResources().getString(R.string.cup),
                getResources().getString(R.string.fluid_ounce),
                getResources().getString(R.string.fluid_ounce_uk),
                getResources().getString(R.string.pint),
                getResources().getString(R.string.pint_uk),
                getResources().getString(R.string.quart),
                getResources().getString(R.string.quart_uk),
                getResources().getString(R.string.gallon),
                getResources().getString(R.string.gallon_uk),
                getResources().getString(R.string.millilitre),
                getResources().getString(R.string.litre)};

        final double[][] cookingValues = {{0.0000049289215938, 202884.136211058},
                {0.0000147867647812, 67628.045403686},
                {0.0002365882365, 4226.7528377304},
                {0.0000295735295625, 33814.0227018429972},
                {0.0000284130625, 35195.07972785404600437},
                {0.000473176473, 2113.37641886518732},
                {0.00056826125, 1759.753986392702300218},
                {0.000946352946, 1056.68820943259366},
                {0.0011365225, 879.8769931963511501092},
                {0.003785411784, 264.172052358148415},
                {0.00454609, 219.9692482990877875273},
                {0.000001, 1000000.0},
                {0.001, 1000.0}};

        final String[] digitalHeaders = {getResources().getString(R.string.bit),
                getResources().getString(R.string.Byte),
                getResources().getString(R.string.kilobit),
                getResources().getString(R.string.kilobyte),
                getResources().getString(R.string.megabit),
                getResources().getString(R.string.megabyte),
                getResources().getString(R.string.gigabit),
                getResources().getString(R.string.gigabyte),
                getResources().getString(R.string.terabit),
                getResources().getString(R.string.terabyte)};

        final double[][] digitalValues = {{0.00000011920928955078, 8388608.0},
                {0.00000095367431640625, 1048576.0},
                {0.0001220703125, 8192.0},
                {0.0009765625, 1024.0},
                {0.125, 8.0},
                {1.0, 1.0},
                {128.0, 0.0078125},
                {1024.0, 0.0009765625},
                {131072.0, 0.00000762939453125},
                {1048576.0, 0.00000095367431640625}};

        final String[] energyHeaders = {getResources().getString(R.string.joule),
                getResources().getString(R.string.kilojoule),
                getResources().getString(R.string.calorie),
                getResources().getString(R.string.kilocalorie),
                getResources().getString(R.string.btu),
                getResources().getString(R.string.ft_lbF),
                getResources().getString(R.string.in_lbF),
                getResources().getString(R.string.kilowatt_hour),
                getResources().getString(R.string.electron_volt)};

        final double[][] energyValues = {{1.0, 1.0},
                {1000.0, 0.001},
                {4.184, 0.2390057361376673040153},
                {4184.0, 0.0002390057361376673040153},
                {1055.05585262, 0.0009478171203133172000128},
                {1.3558179483314004, 0.7375621494575464935503},
                {0.1129848290276167, 8.850745793490557922604},
                {3600000.0, 0.0000002777777777777777777778},
                {0.000000000000000000160217653, 6241509479607718382.9424839}};

        final String[] fuelHeaders = {getResources().getString(R.string.mpg_us),
                getResources().getString(R.string.mpg_uk),
                getResources().getString(R.string.l_100k),
                getResources().getString(R.string.km_l),
                getResources().getString(R.string.miles_l)};

        final double[][] fuelValues = {{1.0, 1.0},
                {0.83267418460479, 1.2009499255398},
                {235.214582, 235.214582},
                {2.352145833, 0.42514370749052},
                {3.7854118, 0.264172052}};

        final String[] lengthHeaders = {getResources().getString(R.string.kilometre),
                getResources().getString(R.string.mile),
                getResources().getString(R.string.metre),
                getResources().getString(R.string.centimetre),
                getResources().getString(R.string.millimetre),
                getResources().getString(R.string.micrometre),
                getResources().getString(R.string.nanometre),
                getResources().getString(R.string.yard),
                getResources().getString(R.string.feet),
                getResources().getString(R.string.inch),
                getResources().getString(R.string.nautical_mile),
                getResources().getString(R.string.furlong),
                getResources().getString(R.string.light_year)};

        final double[][] lengthValues = {{1000.0, 0.001},
                {1609.344, 0.00062137119223733397},
                {1.0, 1.0},
                {0.01, 100.0},
                {0.001, 1000.0},
                {0.000001, 1000000.0},
                {0.000000001, 1000000000.0},
                {0.9144, 1.09361329833770779},
                {0.3048, 3.28083989501312336},
                {0.0254, 39.3700787401574803},
                {1852.0, 0.000539956803455723542},
                {201.168, 0.0049709695379},
                {9460730472580800.0, 0.0000000000000001057000834024615463709}};

        final String[] massHeaders = {getResources().getString(R.string.kilogram),
                getResources().getString(R.string.pound),
                getResources().getString(R.string.gram),
                getResources().getString(R.string.milligram),
                getResources().getString(R.string.ounce),
                getResources().getString(R.string.grain),
                getResources().getString(R.string.stone),
                getResources().getString(R.string.metric_ton),
                getResources().getString(R.string.short_ton),
                getResources().getString(R.string.long_ton)};

        final double[][] massValues = {{1.0, 1.0},
                {0.45359237, 2.20462262184877581},
                {0.001, 1000.0},
                {0.000001, 1000000.0},
                {0.028349523125, 35.27396194958041291568},
                {0.00006479891, 15432.35835294143065061},
                {6.35029318, 0.15747304441777},
                {1000.0, 0.001},
                {907.18474, 0.0011023113109243879},
                {1016.0469088, 0.0009842065276110606282276}};

        final String[] powerHeaders = {getResources().getString(R.string.watt),
                getResources().getString(R.string.kilowatt),
                getResources().getString(R.string.megawatt),
                getResources().getString(R.string.hp),
                getResources().getString(R.string.hp_uk),
                getResources().getString(R.string.ft_lbf_s),
                getResources().getString(R.string.calorie_s),
                getResources().getString(R.string.btu_s),
                getResources().getString(R.string.kva),
                getResources().getString(R.string.electron_volt)};

        final double[][] powerValues = {{1.0, 1.0},
                {1000.0, 0.001},
                {1000000.0, 0.000001},
                {735.49875, 0.00135962161730390432},
                {745.69987158227022, 0.00134102208959502793},
                {1.3558179483314004, 0.737562149277265364},
                {4.1868, 0.23884589662749594},
                {1055.05585262, 0.0009478171203133172},
                {1000.0, 0.001},
                {0.000000000000000000160217653, 6241509479607718382.9424839}};

        final String[] pressureHeaders = {getResources().getString(R.string.megapascal),
                getResources().getString(R.string.kilopascal),
                getResources().getString(R.string.pascal),
                getResources().getString(R.string.bar),
                getResources().getString(R.string.psi),
                getResources().getString(R.string.psf),
                getResources().getString(R.string.atmosphere),
                getResources().getString(R.string.technical_atmosphere),
                getResources().getString(R.string.mmhg),
                getResources().getString(R.string.torr)};

        final double[][] pressureValues = {{1000000.0, 0.000001},
                {1000.0, 0.001},
                {1.0, 1.0},
                {100000.0, 0.00001},
                {6894.757293168361, 0.000145037737730209222},
                {47.880258980335840277777777778, 0.020885434233150127968},
                {101325.0, 0.0000098692326671601283},
                {98066.5, 0.0000101971621297792824257},
                {133.322387415, 0.007500615758456563339513},
                {133.3223684210526315789, 0.00750061682704169751}};

        final String[] speedHeaders = {getResources().getString(R.string.km_h),
                getResources().getString(R.string.mph),
                getResources().getString(R.string.m_s),
                getResources().getString(R.string.fps),
                getResources().getString(R.string.knot)};

        final double[][] speedValues = {{0.27777777777778, 3.6},
                {0.44704, 2.2369362920544},
                {1.0, 1.0},
                {0.3048, 3.2808398950131},
                {0.51444444444444, 1.9438444924406}};

        final String[] timeHeaders = {getResources().getString(R.string.year),
                getResources().getString(R.string.month),
                getResources().getString(R.string.week),
                getResources().getString(R.string.day),
                getResources().getString(R.string.hour),
                getResources().getString(R.string.minute),
                getResources().getString(R.string.second),
                getResources().getString(R.string.millisecond),
                getResources().getString(R.string.nanosecond)};

        final double[][] timeValues = {{31556900.0, 0.000000031688791},
                {2628000.0, 0.0000003805175},
                {604800.0, 0.00000165343915343915344},
                {86400.0, 0.0000115740740740740741},
                {3600.0, 0.000277777777777777778},
                {60.0, 0.0166666666666666667},
                {1.0, 1.0},
                {0.001, 1000.0},
                {0.000000001, 1000000000.0}};

        final String[] torqueHeaders = {getResources().getString(R.string.n_m),
                getResources().getString(R.string.ft_lbF),
                getResources().getString(R.string.in_lbF)};

        final double[][] torqueValues = {{1.0, 1.0},
                {1.3558179483314004, 0.7375621494575464935503},
                {0.1129848290276167, 8.850745793490557922604}};

        final String[] volumeHeaders = {getResources().getString(R.string.teaspoon),
                getResources().getString(R.string.tablespoon),
                getResources().getString(R.string.cup),
                getResources().getString(R.string.fluid_ounce),
                getResources().getString(R.string.fluid_ounce_uk),
                getResources().getString(R.string.pint),
                getResources().getString(R.string.pint_uk),
                getResources().getString(R.string.quart),
                getResources().getString(R.string.quart_uk),
                getResources().getString(R.string.gallon),
                getResources().getString(R.string.gallon_uk),
                getResources().getString(R.string.barrel),
                getResources().getString(R.string.barrel_uk),
                getResources().getString(R.string.millilitre),
                getResources().getString(R.string.litre),
                getResources().getString(R.string.cubic_cm),
                getResources().getString(R.string.cubic_m),
                getResources().getString(R.string.cubic_inch),
                getResources().getString(R.string.cubic_foot),
                getResources().getString(R.string.cubic_yard)};

        final double[][] volumeValues = {{0.0000049289215938, 202884.136211058},
                {0.0000147867647812, 67628.045403686},
                {0.0002365882365, 4226.7528377304},
                {0.0000295735295625, 33814.0227018429972},
                {0.0000284130625, 35195.07972785404600437},
                {0.000473176473, 2113.37641886518732},
                {0.00056826125, 1759.753986392702300218},
                {0.000946352946, 1056.68820943259366},
                {0.0011365225, 879.8769931963511501092},
                {0.003785411784, 264.172052358148415},
                {0.00454609, 219.9692482990877875273},
                {0.119240471196, 8.38641436057614017079},
                {0.16365924, 6.11025689719688298687},
                {0.000001, 1000000.0},
                {0.001, 1000.0},
                {0.000001, 1000000.0},
                {1.0, 1.0},
                {0.000016387064, 61023.744094732284},
                {0.028316846592, 35.3146667214885903},
                {0.7645548692741148, 1.3079506}};

        final TextWatcher textWatcher = new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                int i = 0;
                while (s != values[i].getEditableText()) {
                    i++;
                }

                if (values[i].isFocused()) {
                    int length;
                    double[][] unitValues = new double[20][];
                    switch (unitSpinner.getSelectedItemPosition()) {
                        case 0:
                            length = areaHeaders.length;
                            System.arraycopy(areaValues, 0, unitValues, 0, areaValues.length);
                            break;
                        case 1:
                            length = cookingHeaders.length;
                            System.arraycopy(cookingValues, 0, unitValues, 0, cookingValues.length);
                            break;
                        case 2:
                            length = digitalHeaders.length;
                            System.arraycopy(digitalValues, 0, unitValues, 0, digitalValues.length);
                            break;
                        case 3:
                            length = energyHeaders.length;
                            System.arraycopy(energyValues, 0, unitValues, 0, energyValues.length);
                            break;
                        case 4:
                            length = fuelHeaders.length;
                            System.arraycopy(fuelValues, 0, unitValues, 0, fuelValues.length);
                            break;
                        case 5:
                            length = lengthHeaders.length;
                            System.arraycopy(lengthValues, 0, unitValues, 0, lengthValues.length);
                            break;
                        case 6:
                            length = massHeaders.length;
                            System.arraycopy(massValues, 0, unitValues, 0, massValues.length);
                            break;
                        case 7:
                            length = powerHeaders.length;
                            System.arraycopy(powerValues, 0, unitValues, 0, powerValues.length);
                            break;
                        case 8:
                            length = pressureHeaders.length;
                            System.arraycopy(pressureValues, 0, unitValues, 0, pressureValues.length);
                            break;
                        case 9:
                            length = speedHeaders.length;
                            System.arraycopy(speedValues, 0, unitValues, 0, speedValues.length);
                            break;
                        case 10:
                            length = timeHeaders.length;
                            System.arraycopy(timeValues, 0, unitValues, 0, timeValues.length);
                            break;
                        case 11:
                            length = torqueHeaders.length;
                            System.arraycopy(torqueValues, 0, unitValues, 0, torqueValues.length);
                            break;
                        case 12:
                            length = volumeHeaders.length;
                            System.arraycopy(volumeValues, 0, unitValues, 0, volumeValues.length);
                            break;
                        default:
                            length = areaHeaders.length;
                            System.arraycopy(areaValues, 0, unitValues, 0, areaValues.length);
                            break;
                    }

                    String value = values[i].getText().toString();
                    try {
                        int j = 0;
                        while (j != i) {
                            BigDecimal multiplier = new BigDecimal(unitValues[j][1]).multiply(new BigDecimal(unitValues[i][0]));
                            BigDecimal bdResult = new BigDecimal(Double.parseDouble(value)).multiply(multiplier);
                            double result = bdResult.doubleValue();
                            if (!values[j].getText().toString().equals(String.valueOf(result)))
                                values[j].setText(String.valueOf(result));
                            j++;
                        }
                        j++;
                        while (j < length) {
                            BigDecimal multiplier = new BigDecimal(unitValues[j][1]).multiply(new BigDecimal(unitValues[i][0]));
                            BigDecimal bdResult = new BigDecimal(Double.parseDouble(value)).multiply(multiplier);
                            double result = bdResult.doubleValue();
                            if (!values[j].getText().toString().equals(String.valueOf(result)))
                                values[j].setText(String.valueOf(result));
                            j++;
                        }
                    } catch (Exception e) {
                        //
                    }
                }
            }
        };

        ArrayAdapter<String> adapterUnits = new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_spinner_item, unitsArray);
        adapterUnits.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        unitSpinner.setAdapter(adapterUnits);
        unitSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                unitSpinner.setSelection(position);
                unitSpinnerPosition = unitSpinner.getSelectedItemPosition();
                preferences.edit().putInt("unitSpinnerPosition", unitSpinnerPosition).apply();
                switch (((int) id)) {
                    case 0:
                        setLayout(areaHeaders, headers, values, textWatcher);
                        break;
                    case 1:
                        setLayout(cookingHeaders, headers, values, textWatcher);
                        break;
                    case 2:
                        setLayout(digitalHeaders, headers, values, textWatcher);
                        break;
                    case 3:
                        setLayout(energyHeaders, headers, values, textWatcher);
                        break;
                    case 4:
                        setLayout(fuelHeaders, headers, values, textWatcher);
                        break;
                    case 5:
                        setLayout(lengthHeaders, headers, values, textWatcher);
                        break;
                    case 6:
                        setLayout(massHeaders, headers, values, textWatcher);
                        break;
                    case 7:
                        setLayout(powerHeaders, headers, values, textWatcher);
                        break;
                    case 8:
                        setLayout(pressureHeaders, headers, values, textWatcher);
                        break;
                    case 9:
                        setLayout(speedHeaders, headers, values, textWatcher);
                        break;
                    case 10:
                        setLayout(timeHeaders, headers, values, textWatcher);
                        break;
                    case 11:
                        setLayout(torqueHeaders, headers, values, textWatcher);
                        break;
                    case 12:
                        setLayout(volumeHeaders, headers, values, textWatcher);
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
        unitSpinner.setSelection(preferences.getInt("unitSpinnerPosition", 0));
    }

    public void setLayout(String[] s, TextView[] t, EditText[] e, TextWatcher tw) {
        int i = 0;
        while (i < s.length) {
            t[i].setVisibility(View.VISIBLE);
            t[i].setText(s[i]);
            e[i].setVisibility(View.VISIBLE);
            e[i].addTextChangedListener(tw);
            i++;
        }
        while (i < 20) {
            t[i].setVisibility(View.GONE);
            e[i].setVisibility(View.GONE);
            i++;
        }
    }

    /*private void getTemperatureConversions() {
        List<Unit> units = new ArrayList<Unit>();
        units.add(new TemperatureUnit(CELSIUS, R.string.celsius));
        units.add(new TemperatureUnit(FAHRENHEIT, R.string.fahrenheit));
        units.add(new TemperatureUnit(KELVIN, R.string.kelvin));
        units.add(new TemperatureUnit(RANKINE, R.string.rankine));
        units.add(new TemperatureUnit(DELISLE, R.string.delisle));
        units.add(new TemperatureUnit(NEWTON, R.string.newton));
        units.add(new TemperatureUnit(REAUMUR, R.string.reaumur));
        units.add(new TemperatureUnit(ROMER, R.string.romer));
        units.add(new TemperatureUnit(GAS_MARK, R.string.gas_mark));
        addConversion(Conversion.TEMPERATURE, new Conversion(Conversion.TEMPERATURE, R.string.temperature, units));
    }*/
} public class Utils {

    public static boolean isTelevision(Context context) {
        UiModeManager uiModeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE);
        return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
    }
} public class AutoResizeTextView extends EditText {

    // Minimum text size for this text view
    public static final float MIN_TEXT_SIZE = 20;
    // Our ellipse string
    private static final String mEllipsis = "...";
    // Registered resize listener
    private OnTextResizeListener mTextResizeListener;
    // Flag for text and/or size changes to force a resize
    private boolean mNeedsResize = false;
    // Text size that is set from code. This acts as a starting point for resizing
    private float mTextSize;
    // Temporary upper bounds on the starting text size
    private float mMaxTextSize = 0;
    // Lower bounds for text size
    private float mMinTextSize = MIN_TEXT_SIZE;
    // Text view line spacing multiplier
    private float mSpacingMult = 1.0f;
    // Text view additional line spacing
    private float mSpacingAdd = 0.0f;
    // Add ellipsis to text that overflows at the smallest text size
    private boolean mAddEllipsis = true;

    // Default constructor override
    public AutoResizeTextView(Context context) {
        this(context, null);
    }

    // Default constructor when inflating from XML file
    public AutoResizeTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    // Default constructor override
    public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mTextSize = getTextSize();
    }

    /**
     * When text changes, set the force resize flag to true and reset the text size.
     */
    @Override
    protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
        mNeedsResize = true;
        // Since this view may be reused, it is good to reset the text size
        resetTextSize();
    }

    /**
     * If the text view size changed, set the force resize flag to true
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            mNeedsResize = true;
        }
    }

    /**
     * Register listener to receive resize notifications
     *
     * @param listener
     */
    public void setOnResizeListener(OnTextResizeListener listener) {
        mTextResizeListener = listener;
    }

    /**
     * Override the set text size to update our internal reference values
     */
    @Override
    public void setTextSize(float size) {
        super.setTextSize(size);
        mTextSize = getTextSize();
    }

    /**
     * Override the set text size to update our internal reference values
     */
    @Override
    public void setTextSize(int unit, float size) {
        super.setTextSize(unit, size);
        mTextSize = getTextSize();
    }

    /**
     * Override the set line spacing to update our internal reference values
     */
    @Override
    public void setLineSpacing(float add, float mult) {
        super.setLineSpacing(add, mult);
        mSpacingMult = mult;
        mSpacingAdd = add;
    }

    /**
     * Return upper text size limit
     *
     * @return
     */
    public float getMaxTextSize() {
        return mMaxTextSize;
    }

    /**
     * Set the upper text size limit and invalidate the view
     *
     * @param maxTextSize
     */
    public void setMaxTextSize(float maxTextSize) {
        mMaxTextSize = maxTextSize;
        requestLayout();
        invalidate();
    }

    /**
     * Return lower text size limit
     *
     * @return
     */
    public float getMinTextSize() {
        return mMinTextSize;
    }

    /**
     * Set the lower text size limit and invalidate the view
     *
     * @param minTextSize
     */
    public void setMinTextSize(float minTextSize) {
        mMinTextSize = minTextSize;
        requestLayout();
        invalidate();
    }

    /**
     * Return flag to add ellipsis to text that overflows at the smallest text size
     *
     * @return
     */
    public boolean getAddEllipsis() {
        return mAddEllipsis;
    }

    /**
     * Set flag to add ellipsis to text that overflows at the smallest text size
     *
     * @param addEllipsis
     */
    public void setAddEllipsis(boolean addEllipsis) {
        mAddEllipsis = addEllipsis;
    }

    /**
     * Reset the text to the original size
     */
    public void resetTextSize() {
        if (mTextSize > 0) {
            super.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
            mMaxTextSize = mTextSize;
        }
    }

    /**
     * Resize text after measuring
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (changed || mNeedsResize) {
            int widthLimit = (right - left) - getCompoundPaddingLeft() - getCompoundPaddingRight();
            int heightLimit = (bottom - top) - getCompoundPaddingBottom() - getCompoundPaddingTop();
            resizeText(widthLimit, heightLimit);
        }
        super.onLayout(changed, left, top, right, bottom);
    }

    /**
     * Resize the text size with default width and height
     */
    public void resizeText() {

        int heightLimit = getHeight() - getPaddingBottom() - getPaddingTop();
        int widthLimit = getWidth() - getPaddingLeft() - getPaddingRight();
        resizeText(widthLimit, heightLimit);
    }

    /**
     * Resize the text size with specified width and height
     *
     * @param width
     * @param height
     */
    public void resizeText(int width, int height) {
        CharSequence text = getText();
        // Do not resize if the view does not have dimensions or there is no text
        if (text == null || text.length() == 0 || height <= 0 || width <= 0 || mTextSize == 0) {
            return;
        }

        if (getTransformationMethod() != null) {
            text = getTransformationMethod().getTransformation(text, this);
        }

        // Get the text view's paint object
        TextPaint textPaint = getPaint();

        // Store the current text size
        float oldTextSize = textPaint.getTextSize();
        // If there is a max text size set, use the lesser of that and the default text size
        float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize;

        // Get the required text height
        int textHeight = getTextHeight(text, textPaint, width, targetTextSize);

        // Until we either fit within our text view or we had reached our min text size, incrementally try smaller sizes
        while (textHeight > height && targetTextSize > mMinTextSize) {
            targetTextSize = Math.max(targetTextSize - 2, mMinTextSize);
            textHeight = getTextHeight(text, textPaint, width, targetTextSize);
        }

        // If we had reached our minimum text size and still don't fit, append an ellipsis
        if (mAddEllipsis && targetTextSize == mMinTextSize && textHeight > height) {
            // Draw using a static layout
            // modified: use a copy of TextPaint for measuring
            TextPaint paint = new TextPaint(textPaint);
            // Draw using a static layout
            StaticLayout layout = new StaticLayout(text, paint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false);
            // Check that we have a least one line of rendered text
            if (layout.getLineCount() > 0) {
                // Since the line at the specific vertical position would be cut off,
                // we must trim up to the previous line
                int lastLine = layout.getLineForVertical(height) - 1;
                // If the text would not even fit on a single line, clear it
                if (lastLine < 0) {
                    setText("");
                }
                // Otherwise, trim to the previous line and add an ellipsis
                else {
                    int start = layout.getLineStart(lastLine);
                    int end = layout.getLineEnd(lastLine);
                    float lineWidth = layout.getLineWidth(lastLine);
                    float ellipseWidth = textPaint.measureText(mEllipsis);

                    // Trim characters off until we have enough room to draw the ellipsis
                    while (width < lineWidth + ellipseWidth) {
                        lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString());
                    }
                    setText(text.subSequence(0, end) + mEllipsis);
                }
            }
        }

        // Some devices try to auto adjust line spacing, so force default line spacing
        // and invalidate the layout as a side effect
        setTextSize(TypedValue.COMPLEX_UNIT_PX, targetTextSize);
        setLineSpacing(mSpacingAdd, mSpacingMult);

        // Notify the listener if registered
        if (mTextResizeListener != null) {
            mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize);
        }

        // Reset force resize flag
        mNeedsResize = false;
    }

    // Set the text size of the text paint object and use a static layout to render text off screen before measuring
    private int getTextHeight(CharSequence source, TextPaint paint, int width, float textSize) {
        // modified: make a copy of the original TextPaint object for measuring
        // (apparently the object gets modified while measuring, see also the
        // docs for TextView.getPaint() (which states to access it read-only)
        TextPaint paintCopy = new TextPaint(paint);
        // Update the text paint object
        paintCopy.setTextSize(textSize);
        // Measure using a static layout
        StaticLayout layout = new StaticLayout(source, paintCopy, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
        return layout.getHeight();
    }

    // Interface for resize notifications
    public interface OnTextResizeListener {
        void onTextResize(TextView textView, float oldSize, float newSize);
    }

} public class CalculatorDisplay extends ViewSwitcher implements OnLongClickListener {
    private static final String ATTR_MAX_DIGITS = "maxDigits";
    private static final int DEFAULT_MAX_DIGITS = 10;

    // only these chars are accepted from keyboard
    private static final char[] ACCEPTED_CHARS = "0123456789.+-*/\u2212\u00d7\u00f7()!%^".toCharArray();

    private static final int ANIM_DURATION = 400;

    public enum Scroll {
        UP, DOWN, NONE
    }

    TranslateAnimation inAnimUp;
    TranslateAnimation outAnimUp;
    TranslateAnimation inAnimDown;
    TranslateAnimation outAnimDown;

    private int mMaxDigits = DEFAULT_MAX_DIGITS;
    private final List<String> keywords;

    public CalculatorDisplay(Context context, AttributeSet attrs) {
        super(context, attrs);
        mMaxDigits = attrs.getAttributeIntValue(null, ATTR_MAX_DIGITS, DEFAULT_MAX_DIGITS);
        String sinString = context.getString(R.string.sin);
        String cosString = context.getString(R.string.cos);
        String tanString = context.getString(R.string.tan);
        String arcsinString = context.getString(R.string.arcsin);
        String arccosString = context.getString(R.string.arccos);
        String arctanString = context.getString(R.string.arctan);
        String logString = context.getString(R.string.lg);
        String lnString = context.getString(R.string.ln);
        String modString = context.getString(R.string.mod);
        String dx = context.getString(R.string.dx);
        String dy = context.getString(R.string.dy);

        keywords = Arrays.asList(sinString + "(", cosString + "(", tanString + "(",
                arcsinString.replace(EquationFormatter.POWER, EquationFormatter.PLACEHOLDER) + "(",
                arccosString.replace(EquationFormatter.POWER, EquationFormatter.PLACEHOLDER) + "(",
                arctanString.replace(EquationFormatter.POWER, EquationFormatter.PLACEHOLDER) + "(", logString + "(", modString + "(", lnString + "(", dx, dy);
        setOnLongClickListener(this);
    }

    public int getMaxDigits() {
        return mMaxDigits;
    }

    public void setLogic(Logic logic) {
        NumberKeyListener calculatorKeyListener = new NumberKeyListener() {
            @Override
            public int getInputType() {
                return EditorInfo.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
            }

            @Override
            protected char[] getAcceptedChars() {
                return ACCEPTED_CHARS;
            }

            @Override
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
                /*
                 * the EditText should still accept letters (eg. 'sin') coming
                 * from the on-screen touch buttons, so don't filter anything.
                 */
                return null;
            }

            @Override
            public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
                if(keyCode == KeyEvent.KEYCODE_DEL) {
                    int selectionHandle = getSelectionStart();
                    if(selectionHandle == 0) {
                        // Remove the view in front
                        AdvancedDisplay editor = getAdvancedDisplay();
                        int index = editor.getChildIndex(getActiveEditText());
                        if(index > 0) {
                            editor.removeView(editor.getChildAt(index - 1));
                        }
                    }
                    else {
                        // Check and remove keywords
                        String textBeforeInsertionHandle = getActiveEditText().getText().toString().substring(0, selectionHandle);
                        String textAfterInsertionHandle = getActiveEditText().getText().toString()
                                .substring(selectionHandle, getActiveEditText().getText().toString().length());

                        for(String s : keywords) {
                            if(textBeforeInsertionHandle.endsWith(s)) {
                                int deletionLength = s.length();
                                String text = textBeforeInsertionHandle.substring(0, textBeforeInsertionHandle.length() - deletionLength)
                                        + textAfterInsertionHandle;
                                getActiveEditText().setText(text);
                                setSelection(selectionHandle - deletionLength);
                                return true;
                            }
                        }
                    }
                }
                return super.onKeyDown(view, content, keyCode, event);
            }
        };

        Editable.Factory factory = new CalculatorEditable.Factory(logic);
        for(int i = 0; i < 2; ++i) {
            AdvancedDisplay text = ((ScrollableDisplay) getChildAt(i)).getView();
            text.setLogic(logic);
            text.setEditableFactory(factory);
            text.setKeyListener(calculatorKeyListener);
            text.setLayoutParams(new ScrollableDisplay.LayoutParams(ScrollableDisplay.LayoutParams.WRAP_CONTENT, ScrollableDisplay.LayoutParams.WRAP_CONTENT,
                    Gravity.END | Gravity.CENTER_VERTICAL));
        }
    }

    @Override
    public void setOnKeyListener(OnKeyListener l) {
        getChildAt(0).setOnKeyListener(l);
        getChildAt(1).setOnKeyListener(l);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
        inAnimUp = new TranslateAnimation(0, 0, h, 0);
        inAnimUp.setDuration(ANIM_DURATION);
        outAnimUp = new TranslateAnimation(0, 0, 0, -h);
        outAnimUp.setDuration(ANIM_DURATION);

        inAnimDown = new TranslateAnimation(0, 0, -h, 0);
        inAnimDown.setDuration(ANIM_DURATION);
        outAnimDown = new TranslateAnimation(0, 0, 0, h);
        outAnimDown.setDuration(ANIM_DURATION);
    }

    public AdvancedDisplay getAdvancedDisplay() {
        return ((ScrollableDisplay) getCurrentView()).getView();
    }

    public EditText getActiveEditText() {
        AdvancedDisplay editor = getAdvancedDisplay();
        return editor.getActiveEditText();
    }

    public void insert(String delta) {
        AdvancedDisplay editor = getAdvancedDisplay();
        editor.insert(delta);
    }

    public String getText() {
        AdvancedDisplay text = getAdvancedDisplay();
        return text.getText();
    }

    public void setText(CharSequence text, Scroll dir) {
        if(getText().length() == 0) {
            dir = Scroll.NONE;
        }

        if(dir == Scroll.UP) {
            setInAnimation(inAnimUp);
            setOutAnimation(outAnimUp);
        }
        else if(dir == Scroll.DOWN) {
            setInAnimation(inAnimDown);
            setOutAnimation(outAnimDown);
        }
        else { // Scroll.NONE
            setInAnimation(null);
            setOutAnimation(null);
        }

        AdvancedDisplay editor = ((ScrollableDisplay) getNextView()).getView();
        editor.setText(text.toString());
        showNext();
        getAdvancedDisplay().getLastView().requestFocus();
    }

    public int getSelectionStart() {
        if(getActiveEditText() == null) return 0;
        return getActiveEditText().getSelectionStart();
    }

    private void setSelection(int position) {
        getActiveEditText().setSelection(position);
    }

    @Override
    protected void onFocusChanged(boolean gain, int direction, Rect prev) {
        super.onFocusChanged(gain, direction, prev);
        if(!gain) {
            requestFocus();
        }
    }

    @Override
    public boolean onLongClick(View v) {
        return getAdvancedDisplay().performLongClick();
    }
} public class CalculatorViewPager extends ViewPager {
    private boolean enabled;

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

    public CalculatorViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
    }

    /**
     * ViewPager inherits ViewGroup's default behavior of delayed clicks on its
     * children, but in order to make the calc buttons more responsive we
     * disable that here.
     */
    public boolean shouldDelayChildPressedState() {
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if(this.enabled) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public boolean getPagingEnabled() {
        return enabled;
    }
} public class Cling extends FrameLayout {
    public static final int SHOW_CLING_DURATION = 600;
    public static final int DISMISS_CLING_DURATION = 250;

    public static final String SIMPLE_CLING_DISMISSED_KEY = "cling.simple.dismissed";
    public static final String MATRIX_CLING_DISMISSED_KEY = "cling.matrix.dismissed";
    public static final String HEX_CLING_DISMISSED_KEY = "cling.hex.dismissed";
    public static final String GRAPH_CLING_DISMISSED_KEY = "cling.graph.dismissed";

    private Calculator mCalculator;
    private boolean mIsInitialized;
    private Drawable mBackground;
    private Drawable mPunchThroughGraphic;
    private Drawable mHandTouchGraphic;
    private int mPunchThroughGraphicCenterRadius;
    private float mRevealRadius;
    private int[] mPositionData;
    private boolean mShowHand;
    private boolean mDismissed;

    private Paint mErasePaint;

    public Cling(Context context) {
        this(context, null, 0);
    }

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

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

    public void init(Calculator c, int[] positionData, float revealRadius, boolean showHand) {
        if(!mIsInitialized) {
            mCalculator = c;
            mPositionData = positionData;
            mShowHand = showHand;
            mDismissed = false;

            Resources r = getContext().getResources();
            mPunchThroughGraphic = r.getDrawable(R.drawable.cling);
            mPunchThroughGraphicCenterRadius = r.getDimensionPixelSize(R.dimen.clingPunchThroughGraphicCenterRadius);
            mRevealRadius = revealRadius;

            mErasePaint = new Paint();
            mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
            mErasePaint.setColor(0xFFFFFF);
            mErasePaint.setAlpha(0);

            mIsInitialized = true;
        }
    }

    public void dismiss() {
        mDismissed = true;
    }

    boolean isDismissed() {
        return mDismissed;
    }

    public void cleanup() {
        mBackground = null;
        mPunchThroughGraphic = null;
        mHandTouchGraphic = null;
        mIsInitialized = false;
    }

    private int[] getPunchThroughPosition() {
        if(mPositionData != null) {
            return mPositionData;
        }
        return new int[] { -1, -1, -1 };
    }

    @Override
    public boolean onTouchEvent(android.view.MotionEvent event) {
        int[] pos = getPunchThroughPosition();
        double diff = Math.sqrt(Math.pow(event.getX() - pos[0], 2) + Math.pow(event.getY() - pos[1], 2));
        if(diff < mRevealRadius) {
            return false;
        }
        return true;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if(mIsInitialized) {
            DisplayMetrics metrics = new DisplayMetrics();
            mCalculator.getWindowManager().getDefaultDisplay().getMetrics(metrics);

            // Initialize the draw buffer (to allow punching through)
            Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(b);

            // Draw the background
            if(mBackground == null) {
                mBackground = getResources().getDrawable(R.drawable.bg_cling);
            }
            if(mBackground != null) {
                mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
                mBackground.draw(c);
            }
            else {
                c.drawColor(0x99000000);
            }

            int cx = -1;
            int cy = -1;
            int cz = -1;
            float scale = mRevealRadius / mPunchThroughGraphicCenterRadius;
            int dw = (int) (scale * mPunchThroughGraphic.getIntrinsicWidth());
            int dh = (int) (scale * mPunchThroughGraphic.getIntrinsicHeight());

            // Determine where to draw the punch through graphic
            Rect rect = new Rect();
            Window window = ((Activity) getContext()).getWindow();
            window.getDecorView().getWindowVisibleDisplayFrame(rect);
            int statusBarHeight = 150;
            int[] pos = getPunchThroughPosition();
            cx = pos[0];
            cy = pos[1] - statusBarHeight;
            cz = pos[2];
            if(cx > -1 && cy > -1 && scale > 0) {
                c.drawCircle(cx, cy, mRevealRadius, mErasePaint);
                mPunchThroughGraphic.setBounds(cx - dw / 2, cy - dh / 2, cx + dw / 2, cy + dh / 2);
                mPunchThroughGraphic.draw(c);
            }

            // Draw the hand graphic
            if(mShowHand) {
                if(mHandTouchGraphic == null) {
                    mHandTouchGraphic = getResources().getDrawable(R.drawable.hand);
                }
                int offset = cz;
                mHandTouchGraphic.setBounds(cx + offset, cy + offset, cx + mHandTouchGraphic.getIntrinsicWidth() + offset,
                        cy + mHandTouchGraphic.getIntrinsicHeight() + offset);
                mHandTouchGraphic.draw(c);
            }

            canvas.drawBitmap(b, 0, 0, null);
            c.setBitmap(null);
            b = null;
        }

        // Draw the rest of the cling
        super.dispatchDraw(canvas);
    }
} public class HistoryLine extends LinearLayout {
    private static final int COPY = 0;
    private static final int COPY_BASE = 1;
    private static final int COPY_EDITED = 2;
    private static final int REMOVE = 3;
    private String[] mMenuItemsStrings;
    private HistoryEntry mHistoryEntry;
    private History mHistory;
    private BaseAdapter mAdapter;

    public HistoryLine(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu) {
        MenuHandler handler = new MenuHandler();
        if(mMenuItemsStrings == null) {
            Resources resources = getResources();
            mMenuItemsStrings = new String[4];
            mMenuItemsStrings[COPY] = String.format(resources.getString(R.string.copy), mHistoryEntry.getBase() + "=" + mHistoryEntry.getEdited());
            mMenuItemsStrings[COPY_BASE] = String.format(resources.getString(R.string.copy), mHistoryEntry.getBase());
            mMenuItemsStrings[COPY_EDITED] = String.format(resources.getString(R.string.copy), mHistoryEntry.getEdited());
            mMenuItemsStrings[REMOVE] = resources.getString(R.string.remove_from_history);
        }
        for(int i = 0; i < mMenuItemsStrings.length; i++) {
            menu.add(Menu.NONE, i, i, mMenuItemsStrings[i]).setOnMenuItemClickListener(handler);
        }
    }

    private class MenuHandler implements MenuItem.OnMenuItemClickListener {
        public boolean onMenuItemClick(MenuItem item) {
            return onTextContextMenuItem(item.getTitle());
        }
    }

    public boolean onTextContextMenuItem(CharSequence title) {
        boolean handled = false;
        if(TextUtils.equals(title, mMenuItemsStrings[COPY])) {
            copyContent(mHistoryEntry.getBase() + "=" + mHistoryEntry.getEdited());
            handled = true;
        }
        else if(TextUtils.equals(title, mMenuItemsStrings[COPY_BASE])) {
            copyContent(mHistoryEntry.getBase());
            handled = true;
        }
        else if(TextUtils.equals(title, mMenuItemsStrings[COPY_EDITED])) {
            copyContent(mHistoryEntry.getEdited());
            handled = true;
        }
        else if(TextUtils.equals(title, mMenuItemsStrings[REMOVE])) {
            removeContent();
            handled = true;
        }
        return handled;
    }

    public void copyContent(String content) {
        ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
        clipboard.setPrimaryClip(ClipData.newPlainText(null, content));
        String toastText = String.format(getResources().getString(R.string.text_copied_toast), content);
        Toast.makeText(getContext(), toastText, Toast.LENGTH_SHORT).show();
    }

    private void removeContent() {
        mHistory.remove(mHistoryEntry);
        mAdapter.notifyDataSetChanged();
    }

    public HistoryEntry getHistoryEntry() {
        return mHistoryEntry;
    }

    public void setHistoryEntry(HistoryEntry historyEntry) {
        this.mHistoryEntry = historyEntry;
    }

    public History getHistory() {
        return mHistory;
    }

    public void setHistory(History history) {
        this.mHistory = history;
    }

    public BaseAdapter getAdapter() {
        return mAdapter;
    }

    public void setAdapter(BaseAdapter adapter) {
        this.mAdapter = adapter;
    }

    public void showMenu() {
        showContextMenu();
    }
} public enum Base {
    BINARY(2),
    OCTAL(8),
    DECIMAL(10),
    HEXADECIMAL(16);

    int quickSerializable;

    Base(int num) {
        this.quickSerializable = num;
    }

    public int getQuickSerializable() {
        return quickSerializable;
    }
} public class Constants {
    public static final String INFINITY_UNICODE = "\u221e";
    // Double.toString() for Infinity
    public static final String INFINITY = "Infinity";
    // Double.toString() for NaN
    public static final String NAN = "NaN";
    public static final char MINUS = '\u2212';
    public static final char MUL = '*';
    //DONE : public static final char MUL = '\u00d7';
    public static final char PLUS = '+';
    public static final char DIV = '/';
    //DONE : public static final char DIV = '\u00f7';
    public static final char POWER_PLACEHOLDER = '\u200B';
    public static final char POWER = '^';
    public static final char EQUAL = '=';
    public static final char LEFT_PAREN = '(';
    public static final char RIGHT_PAREN = ')';
    public static char DECIMAL_POINT;
    public static char DECIMAL_SEPARATOR;
    public static char BINARY_SEPARATOR;
    public static char OCTAL_SEPARATOR;
    public static char HEXADECIMAL_SEPARATOR;
    public static char MATRIX_SEPARATOR;
    public static String REGEX_NUMBER;
    public static String REGEX_NOT_NUMBER;
    // Values for decimals and comas
    private static DecimalFormatSymbols DECIMAL_FORMAT;

    static {
        rebuildConstants();
    }

    /**
     * If the locale changes, but the app is still in memory, you may need to rebuild these constants
     */
    public static void rebuildConstants() {
        DECIMAL_FORMAT = new DecimalFormatSymbols();

        // These will already be known by Java
        DECIMAL_POINT = DECIMAL_FORMAT.getDecimalSeparator();
        DECIMAL_SEPARATOR = DECIMAL_FORMAT.getGroupingSeparator();

        // Use a space for Bin and Hex
        BINARY_SEPARATOR = ' ';
        OCTAL_SEPARATOR = ' ';
        HEXADECIMAL_SEPARATOR = ' ';

        // We have to be careful with the Matrix Separator.
        // It defaults to "," but that's a common decimal point.
        if (DECIMAL_POINT == ',') MATRIX_SEPARATOR = ' ';
        else MATRIX_SEPARATOR = ',';

        String number = "A-F0-9" +
                Pattern.quote(String.valueOf(DECIMAL_POINT)) +
                Pattern.quote(String.valueOf(DECIMAL_SEPARATOR)) +
                Pattern.quote(String.valueOf(BINARY_SEPARATOR)) +
                Pattern.quote(String.valueOf(OCTAL_SEPARATOR)) +
                Pattern.quote(String.valueOf(HEXADECIMAL_SEPARATOR));

        REGEX_NUMBER = "[" + number + "]";
        REGEX_NOT_NUMBER = "[^" + number + "]";
    }
} public class Solver {
    // Used for solving basic math
    private static final Symbols sSymbols = new Symbols();
    private BaseModule mBaseModule;
    private MatrixModule mMatrixModule;
    private GraphModule mGraphModule;
    private int mLineLength = 15;
    //DONE : private int mLineLength = 8;
    private Localizer mLocalizer;

    public Solver() {
        mBaseModule = new BaseModule(this);
        mMatrixModule = new MatrixModule(this);
        mGraphModule = new GraphModule(this);
    }

    public static boolean equal(String a, String b) {
        return clean(a).equals(clean(b));
    }

    public static String clean(String equation) {
        return equation
                .replace('-', Constants.MINUS)
                .replace('/', Constants.DIV)
                .replace('*', Constants.MUL)
                .replace(Constants.INFINITY, Constants.INFINITY_UNICODE);
    }

    public static boolean isOperator(char c) {
        return ("" +
                Constants.PLUS +
                Constants.MINUS +
                Constants.DIV +
                Constants.MUL +
                Constants.POWER).indexOf(c) != -1;
    }

    public static boolean isOperator(String c) {
        return isOperator(c.charAt(0));
    }

    public static boolean isNegative(String number) {
        return number.startsWith(String.valueOf(Constants.MINUS)) || number.startsWith("-");
    }

    public static boolean isDigit(char number) {
        return String.valueOf(number).matches(Constants.REGEX_NUMBER);
    }

    /**
     * Input an equation as a string
     * ex: sin(150)
     * and get the result returned.
     */
    public String solve(String input) throws SyntaxException {
        if (displayContainsMatrices(input)) {
            return mMatrixModule.evaluateMatrices(input);
        }

        if (input.trim().isEmpty()) {
            return "";
        }

        if (mLocalizer != null) input = mLocalizer.localize(input);

        // Drop final operators (they can only result in error)
        int size = input.length();
        while (size > 0 && isOperator(input.charAt(size - 1))) {
            input = input.substring(0, size - 1);
            --size;
        }

        // Convert to decimal
        String decimalInput = convertToDecimal(input);

        Complex value = sSymbols.evalComplex(decimalInput);

        String real = "";
        for (int precision = mLineLength; precision > 6; precision--) {
            real = tryFormattingWithPrecision(value.re, precision);
            if (real.length() <= mLineLength) {
                break;
            }
        }

        String imaginary = "";
        for (int precision = mLineLength; precision > 6; precision--) {
            imaginary = tryFormattingWithPrecision(value.im, precision);
            if (imaginary.length() <= mLineLength) {
                break;
            }
        }

        real = clean(mBaseModule.changeBase(real, Base.DECIMAL, mBaseModule.getBase()));
        imaginary = clean(mBaseModule.changeBase(imaginary, Base.DECIMAL, mBaseModule.getBase()));

        String result = "";
        if (value.re != 0 && value.im == 1) result = real + "+" + "i";
        else if (value.re != 0 && value.im > 0) result = real + "+" + imaginary + "i";
        else if (value.re != 0 && value.im == -1) result = real + "-" + "i";
        else if (value.re != 0 && value.im < 0) result = real + imaginary + "i"; // Implicit -
        else if (value.re != 0 && value.im == 0) result = real;
        else if (value.re == 0 && value.im == 1) result = "i";
        else if (value.re == 0 && value.im == -1) result = "-i";
        else if (value.re == 0 && value.im != 0) result = imaginary + "i";
        else if (value.re == 0 && value.im == 0) result = "0";

        if (mLocalizer != null) result = mLocalizer.relocalize(result);

        return result;
    }

    public double eval(String input) throws SyntaxException {
        return sSymbols.eval(input);
    }

    public void pushFrame() {
        sSymbols.pushFrame();
    }

    public void popFrame() {
        sSymbols.popFrame();
    }

    public void define(String var, double val) {
        sSymbols.define(var, val);
    }

    boolean displayContainsMatrices(String text) {
        return getMatrixModule().isMatrix(text);
    }

    public String convertToDecimal(String input) throws SyntaxException {
        return mBaseModule.changeBase(input, mBaseModule.getBase(), Base.DECIMAL);
    }

    String tryFormattingWithPrecision(double value, int precision) throws SyntaxException {
        if (Double.isNaN(value)) {
            throw new SyntaxException();
        }

        // The standard scientific formatter is basically what we need. We will
        // start with what it produces and then massage it a bit.
        String result = String.format(Locale.US, "%" + mLineLength + "." + precision + "g", value);
        String mantissa = result;
        String exponent = null;
        int e = result.indexOf('e');
        if (e != -1) {
            mantissa = result.substring(0, e);

            // Strip "+" and unnecessary 0's from the exponent
            exponent = result.substring(e + 1);
            if (exponent.startsWith("+")) {
                exponent = exponent.substring(1);
            }
            exponent = String.valueOf(Integer.parseInt(exponent));
        }

        int period = mantissa.indexOf('.');
        if (period == -1) {
            period = mantissa.indexOf(',');
        }
        if (period != -1) {
            // Strip trailing 0's
            while (mantissa.length() > 0 && mantissa.endsWith("0")) {
                mantissa = mantissa.substring(0, mantissa.length() - 1);
            }
            if (mantissa.length() == period + 1) {
                mantissa = mantissa.substring(0, mantissa.length() - 1);
            }
        }

        if (exponent != null) {
            result = mantissa + 'e' + exponent;
        } else {
            result = mantissa;
        }
        return result;
    }

    public void enableLocalization(Context context, Class r) {
        mLocalizer = new Localizer(context, r);
    }

    public void setLineLength(int length) {
        mLineLength = length;
    }

    public Base getBase() {
        return mBaseModule.getBase();
    }

    public void setBase(Base base) {
        mBaseModule.setBase(base);
    }

    public BaseModule getBaseModule() {
        return mBaseModule;
    }

    public MatrixModule getMatrixModule() {
        return mMatrixModule;
    }

    public GraphModule getGraphModule() {
        return mGraphModule;
    }

    public Symbols getSymbols() {
        return sSymbols;
    }
} @SuppressWarnings("UnusedDeclaration")
public class ChangeLog {
    /**
     * Tag that is used when sending error/debug messages to the log.
     */
    protected static final String LOG_TAG = "ckChangeLog";

    /**
     * This is the key used when storing the version code in SharedPreferences.
     */
    protected static final String VERSION_KEY = "ckChangeLog_last_version_code";

    /**
     * Constant that used when no version code is available.
     */
    protected static final int NO_VERSION = -1;

    /**
     * Default CSS styles used to format the change log.
     */
    public static final String DEFAULT_CSS =
            "h1 { margin-left: 15px; margin-top: 15px; margin-bottom: -5px; font-size: 1.15em; }" + "\n" +
            "h2 { margin-left: 15px; margin-top: 5px; margin-bottom: -5px; font-size: 0.9em; font-weight: normal; font-style: italic; }" + "\n" +
            "li { margin-left: 0px; }" + "\n" +
            "ul { padding-left: 2em; }";


    /**
     * Context that is used to access the resources and to create the ChangeLog dialogs.
     */
    protected final Context mContext;

    /**
     * Contains the CSS rules used to format the change log.
     */
    protected final String mCss;

    /**
     * Last version code read from {@code SharedPreferences} or {@link #NO_VERSION}.
     */
    private int mLastVersionCode;

    /**
     * Version code of the current installation.
     */
    private int mCurrentVersionCode;

    /**
     * Version name of the current installation.
     */
    private String mCurrentVersionName;


    /**
     * Contains constants for the root element of {@code changelog.xml}.
     */
    protected interface ChangeLogTag {
        static final String NAME = "changelog";
    }

    /**
     * Contains constants for the release element of {@code changelog.xml}.
     */
    protected interface ReleaseTag {
        static final String NAME = "release";
        static final String ATTRIBUTE_VERSION = "version";
        static final String ATTRIBUTE_VERSION_CODE = "versioncode";
        static final String ATTRIBUTE_DATE = "date";
    }

    /**
     * Contains constants for the change element of {@code changelog.xml}.
     */
    protected interface ChangeTag {
        static final String NAME = "change";
    }

    /**
     * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file.
     *
     * @param context
     *         Context that is used to access the resources and to create the ChangeLog dialogs.
     */
    public ChangeLog(Context context) {
        this(context, PreferenceManager.getDefaultSharedPreferences(context), DEFAULT_CSS);
    }

    /**
     * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file.
     *
     * @param context
     *         Context that is used to access the resources and to create the ChangeLog dialogs.
     * @param css
     *         CSS styles that will be used to format the change log.
     */
    public ChangeLog(Context context, String css) {
        this(context, PreferenceManager.getDefaultSharedPreferences(context), css);
    }

    /**
     * Create a {@code ChangeLog} instance using the supplied {@code SharedPreferences} instance.
     *
     * @param context
     *         Context that is used to access the resources and to create the ChangeLog dialogs.
     * @param preferences
     *         {@code SharedPreferences} instance that is used to persist the last version code.
     * @param css
     *         CSS styles used to format the change log (excluding {@code <style>} and
     *         {@code </style>}).
     *
     */
    public ChangeLog(Context context, SharedPreferences preferences, String css) {
        mContext = context;
        mCss = css;

        // Get last version code
        mLastVersionCode = preferences.getInt(VERSION_KEY, NO_VERSION);

        // Get current version code and version name
        try {
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), 0);

            mCurrentVersionCode = packageInfo.versionCode;
            mCurrentVersionName = packageInfo.versionName;
        } catch (NameNotFoundException e) {
            mCurrentVersionCode = NO_VERSION;
            Log.e(LOG_TAG, "Could not get version information from manifest!", e);
        }
    }

    /**
     * Get version code of last installation.
     *
     * @return The version code of the last installation of this app (as described in the former
     *         manifest). This will be the same as returned by {@link #getCurrentVersionCode()} the
     *         second time this version of the app is launched (more precisely: the second time
     *         {@code ChangeLog} is instantiated).
     *
     * @see <a href="http://developer.android.com/guide/topics/manifest/manifest-element.html#vcode">android:versionCode</a>
     */
    public int getLastVersionCode() {
        return mLastVersionCode;
    }

    /**
     * Get version code of current installation.
     *
     * @return The version code of this app as described in the manifest.
     *
     * @see <a href="http://developer.android.com/guide/topics/manifest/manifest-element.html#vcode">android:versionCode</a>
     */
    public int getCurrentVersionCode() {
        return mCurrentVersionCode;
    }

    /**
     * Get version name of current installation.
     *
     * @return The version name of this app as described in the manifest.
     *
     * @see <a href="http://developer.android.com/guide/topics/manifest/manifest-element.html#vname">android:versionName</a>
     */
    public String getCurrentVersionName() {
        return mCurrentVersionName;
    }

    /**
     * Check if this is the first execution of this app version.
     *
     * @return {@code true} if this version of your app is started the first time.
     */
    public boolean isFirstRun() {
        return mLastVersionCode < mCurrentVersionCode;
    }

    /**
     * Check if this is a new installation.
     *
     * @return {@code true} if your app including {@code ChangeLog} is started the first time ever.
     *         Also {@code true} if your app was uninstalled and installed again.
     */
    public boolean isFirstRunEver() {
        return mLastVersionCode == NO_VERSION;
    }

    /**
     * Skip the "What's new" dialog for this app version.
     *
     * <p>
     * Future calls to {@link #isFirstRun()} and {@link #isFirstRunEver()} will return {@code false}
     * for the current app version.
     * </p>
     */
    public void skipLogDialog() {
        updateVersionInPreferences();
    }

    /**
     * Get the "What's New" dialog.
     *
     * @return An AlertDialog displaying the changes since the previous installed version of your
     *         app (What's New). But when this is the first run of your app including
     *         {@code ChangeLog} then the full log dialog is show.
     */
    public AlertDialog getLogDialog() {
        return getDialog(isFirstRunEver());
    }

    /**
     * Get a dialog with the full change log.
     *
     * @return An AlertDialog with a full change log displayed.
     */
    public AlertDialog getFullLogDialog() {
        return getDialog(true);
    }

    /**
     * Create a dialog containing (parts of the) change log.
     *
     * @param full
     *         If this is {@code true} the full change log is displayed. Otherwise only changes for
     *         versions newer than the last version are displayed.
     *
     * @return A dialog containing the (partial) change log.
     */
    protected AlertDialog getDialog(boolean full) {
        TextView title = new TextView(mContext);
        title.setText(Html.fromHtml("<b>" + mContext.getResources().getString(
                full ? R.string.changelog_full_title : R.string.changelog_title, Html.fromHtml("</b>"))));
        title.setPadding(50, 20, 30, 20);
        title.setTextSize(23);
        title.setGravity(Gravity.START);
        title.setTextColor(ContextCompat.getColor(mContext, R.color.maindigitbacks));
        WebView wv = new WebView(mContext);
        //wv.setBackgroundColor(0); // transparent
        wv.loadDataWithBaseURL(null, getLog(full), "text/html", "UTF-8", null);

        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setCustomTitle(title)
                .setView(wv)
                .setCancelable(false)
                // OK button
                .setPositiveButton(
                        mContext.getResources().getString(R.string.changelog_ok_button),
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                // The user clicked "OK" so save the current version code as
                                // "last version code".
                                updateVersionInPreferences();
                            }
                        });

        if (!full) {
            // Show "More…" button if we're only displaying a partial change log.
            builder.setNegativeButton(R.string.changelog_show_full,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int id) {
                            getFullLogDialog().show();
                        }
                    });
        }

        return builder.create();
    }

    /**
     * Write current version code to the preferences.
     */
    protected void updateVersionInPreferences() {
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
        SharedPreferences.Editor editor = sp.edit();
        editor.putInt(VERSION_KEY, mCurrentVersionCode);

        // TODO: Update preferences from a background thread
        editor.commit();
    }

    /**
     * Get changes since last version as HTML string.
     *
     * @return HTML string containing the changes since the previous installed version of your app
     *         (What's New).
     */
    public String getLog() {
        return getLog(false);
    }

    /**
     * Get full change log as HTML string.
     *
     * @return HTML string containing the full change log.
     */
    public String getFullLog() {
        return getLog(true);
    }

    /**
     * Get (partial) change log as HTML string.
     *
     * @param full
     *         If this is {@code true} the full change log is returned. Otherwise only changes for
     *         versions newer than the last version are returned.
     *
     * @return The (partial) change log.
     */
    protected String getLog(boolean full) {
        StringBuilder sb = new StringBuilder();

        sb.append("<html><head><style type=\"text/css\">");
        sb.append(mCss);
        sb.append("</style></head><body>");

        String versionFormat = mContext.getResources().getString(R.string.changelog_version_format) + " " + mCurrentVersionName;

        List<ReleaseItem> changelog = getChangeLog(full);

        for (ReleaseItem release : changelog) {
            sb.append("<h1>");
            sb.append(String.format(versionFormat, mCurrentVersionName));
            sb.append("</h1><h2>");
            sb.append(release.date);
            sb.append("</h2><ul>");
            for (String change : release.changes) {
                sb.append("<li>");
                sb.append(change);
                sb.append("</li>");
            }
            sb.append("</ul>");
        }

        sb.append("</body></html>");

        return sb.toString();
    }

    /**
     * Returns the merged change log.
     *
     * @param full
     *         If this is {@code true} the full change log is returned. Otherwise only changes for
     *         versions newer than the last version are returned.
     *
     * @return A sorted {@code List} containing {@link ReleaseItem}s representing the (partial)
     *         change log.
     *
     * @see #getChangeLogComparator()
     */
    public List<ReleaseItem> getChangeLog(boolean full) {
        SparseArray<ReleaseItem> masterChangelog = getMasterChangeLog(full);
        SparseArray<ReleaseItem> changelog = getLocalizedChangeLog(full);

        List<ReleaseItem> mergedChangeLog =
                new ArrayList<ReleaseItem>(masterChangelog.size());

        for (int i = 0, len = masterChangelog.size(); i < len; i++) {
            int key = masterChangelog.keyAt(i);

            // Use release information from localized change log and fall back to the master file
            // if necessary.
            ReleaseItem release = changelog.get(key, masterChangelog.get(key));

            mergedChangeLog.add(release);
        }

        Collections.sort(mergedChangeLog, getChangeLogComparator());

        return mergedChangeLog;
    }

    /**
     * Read master change log from {@code xml/changelog_master.xml}
     *
     * @see #readChangeLogFromResource(int, boolean)
     */
    protected SparseArray<ReleaseItem> getMasterChangeLog(boolean full) {
        return readChangeLogFromResource(R.xml.changelog_master, full);
    }

    /**
     * Read localized change log from {@code xml[-lang]/changelog.xml}
     *
     * @see #readChangeLogFromResource(int, boolean)
     */
    protected SparseArray<ReleaseItem> getLocalizedChangeLog(boolean full) {
        return readChangeLogFromResource(R.xml.changelog, full);
    }

    /**
     * Read change log from XML resource file.
     *
     * @param resId
     *         Resource ID of the XML file to read the change log from.
     * @param full
     *         If this is {@code true} the full change log is returned. Otherwise only changes for
     *         versions newer than the last version are returned.
     *
     * @return A {@code SparseArray} containing {@link ReleaseItem}s representing the (partial)
     *         change log.
     */
    protected final SparseArray<ReleaseItem> readChangeLogFromResource(int resId, boolean full) {
        XmlResourceParser xml = mContext.getResources().getXml(resId);
        try {
            return readChangeLog(xml, full);
        } finally {
            xml.close();
        }
    }

    /**
     * Read the change log from an XML file.
     *
     * @param xml
     *         The {@code XmlPullParser} instance used to read the change log.
     * @param full
     *         If {@code true} the full change log is read. Otherwise only the changes since the
     *         last (saved) version are read.
     *
     * @return A {@code SparseArray} mapping the version codes to release information.
     */
    protected SparseArray<ReleaseItem> readChangeLog(XmlPullParser xml, boolean full) {
        SparseArray<ReleaseItem> result = new SparseArray<ReleaseItem>();

        try {
            int eventType = xml.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ReleaseTag.NAME)) {
                    if (parseReleaseTag(xml, full, result)) {
                        // Stop reading more elements if this entry is not newer than the last
                        // version.
                        break;
                    }
                }
                eventType = xml.next();
            }
        } catch (XmlPullParserException e) {
            Log.e(LOG_TAG, e.getMessage(), e);
        } catch (IOException e) {
            Log.e(LOG_TAG, e.getMessage(), e);
        }

        return result;
    }

    /**
     * Parse the {@code release} tag of a change log XML file.
     *
     * @param xml
     *         The {@code XmlPullParser} instance used to read the change log.
     * @param full
     *         If {@code true} the contents of the {@code release} tag are always added to
     *         {@code changelog}. Otherwise only if the item's {@code versioncode} attribute is
     *         higher than the last version code.
     * @param changelog
     *         The {@code SparseArray} to add a new {@link ReleaseItem} instance to.
     *
     * @return {@code true} if the {@code release} element is describing changes of a version older
     *         or equal to the last version. In that case {@code changelog} won't be modified and
     *         {@link #readChangeLog(XmlPullParser, boolean)} will stop reading more elements from
     *         the change log file.
     *
     * @throws XmlPullParserException
     * @throws IOException
     */
    private boolean parseReleaseTag(XmlPullParser xml, boolean full,
            SparseArray<ReleaseItem> changelog) throws XmlPullParserException, IOException {

        String version = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION);
        String date = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_DATE);

        int versionCode;
        try {
            String versionCodeStr = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION_CODE);
            versionCode = Integer.parseInt(versionCodeStr);
        } catch (NumberFormatException e) {
            versionCode = NO_VERSION;
        }

        if (!full && versionCode <= mLastVersionCode) {
            return true;
        }

        int eventType = xml.getEventType();
        List<String> changes = new ArrayList<String>();
        while (eventType != XmlPullParser.END_TAG || xml.getName().equals(ChangeTag.NAME)) {
            if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ChangeTag.NAME)) {
                eventType = xml.next();

                changes.add(xml.getText());
            }
            eventType = xml.next();
        }

        ReleaseItem release = new ReleaseItem(versionCode, version, date, changes);
        changelog.put(versionCode, release);

        return false;
    }

    /**
     * Returns a {@link Comparator} that specifies the sort order of the {@link ReleaseItem}s.
     *
     * <p>
     * The default implementation returns the items in reverse order (latest version first).
     * </p>
     */
    protected Comparator<ReleaseItem> getChangeLogComparator() {
        return new Comparator<ReleaseItem>() {
            @Override
            public int compare(ReleaseItem lhs, ReleaseItem rhs) {
                if (lhs.versionCode < rhs.versionCode) {
                    return 1;
                } else if (lhs.versionCode > rhs.versionCode) {
                    return -1;
                } else {
                    return 0;
                }
            }
        };
    }

    /**
     * Container used to store information about a release/version.
     */
    public static class ReleaseItem {
        /**
         * Version code of the release.
         */
        public final int versionCode;

        /**
         * Version name of the release.
         */
        public final String versionName;
        public final String date;

        /**
         * List of changes introduced with that release.
         */
        public final List<String> changes;

        ReleaseItem(int versionCode, String versionName, String date, List<String> changes) {
            this.versionCode = versionCode;
            this.versionName = versionName;
            this.changes = changes;
            this.date = date;
        }
    }
}
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Point;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.ActionBarDrawerToggle;
import android.text.InputType;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Display;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.Spinner;
import android.widget.Toast;
import com.gigabytedevelopersinc.app.calculator.fragments.ConverterFragment;
import com.gigabytedevelopersinc.app.calculator.fragments.CurrencyFragment;
import com.gigabytedevelopersinc.app.calculator.fragments.DateFragment;
import com.gigabytedevelopersinc.app.calculator.fragments.UnitsFragment;
import com.gigabytedevelopersinc.app.calculator.misc.Utils;
import com.gigabytedevelopersinc.app.calculator.util.AutoResizeTextView;
import com.gigabytedevelopersinc.app.calculator.view.CalculatorDisplay;
import com.gigabytedevelopersinc.app.calculator.view.CalculatorViewPager;
import com.gigabytedevelopersinc.app.calculator.view.Cling;
import com.gigabytedevelopersinc.app.calculator.view.HistoryLine;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
import com.xlythe.math.Base;
import com.xlythe.math.Constants;
import com.xlythe.math.Solver;
import com.xlythe.slider.Slider;
import com.xlythe.slider.Slider.Direction;
import org.javia.arity.SyntaxException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Locale;
import javax.sql.DataSource;
import com.gigabytedevelopersinc.app.calculator.util.ChangeLog;
            mPager.setCurrentItem(state == null ? Panel.BASIC.getOrder() : state.getInt(STATE_CURRENT_VIEW, Panel.BASIC.getOrder()));
            mPager.addOnPageChangeListener(this);
            runCling(false);
            mListener.setHandler(this, mLogic, mPager);
        }
        else if(mSmallPager != null && mLargePager != null) {
            // Expanded UI
            mSmallPager.setAdapter(new SmallPageAdapter(mSmallPager, mLogic));
            mLargePager.setAdapter(new LargePageAdapter(mLargePager, mGraph, mLogic));
            mSmallPager.setCurrentItem(state == null ? SmallPanel.ADVANCED.getOrder() : state.getInt(STATE_CURRENT_VIEW_SMALL, SmallPanel.ADVANCED.getOrder()));
            mLargePager.setCurrentItem(state == null ? LargePanel.BASIC.getOrder() : state.getInt(STATE_CURRENT_VIEW_LARGE, LargePanel.BASIC.getOrder()));
            mSmallPager.addOnPageChangeListener(this);
            mLargePager.addOnPageChangeListener(this);
            runCling(false);
            mListener.setHandler(this, mLogic, mSmallPager, mLargePager);
        }

        mDisplay.setOnKeyListener(mListener);

        if(!ViewConfiguration.get(this).hasPermanentMenuKey()) {
            createFakeMenu();
        }

        mLogic.resumeWithHistory();
        updateDeleteMode();

        mPulldown.bringToFront();
    }
    @Override
    protected void onStart() {
        super.onStart();
        ChangeLog changeLog = new ChangeLog(this);
        if (changeLog.isFirstRun()) {
            changeLog.getFullLogDialog().show();
        }
    }

    private void updateDeleteMode() {
        if(mLogic.getDeleteMode() == Logic.DELETE_MODE_BACKSPACE) {
            mClearButton.setVisibility(View.GONE);
            mBackspaceButton.setVisibility(View.VISIBLE);
        }
        else {
            mClearButton.setVisibility(View.VISIBLE);
            mBackspaceButton.setVisibility(View.GONE);
        }
    }

    private void addDrawerItems() {
        String[] osArray = { "Main Calculator", "Unit Converter", "Currency Converter", "Date and Time Calculator", "Advanced Unit Converter", "Algebra" };
        mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, osArray);
        mDrawerList.setAdapter(mAdapter);

        mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Fragment fragment;
                switch (position){
                    case 0:
                        if (mInterstitialAd.isLoaded()) {
                            mInterstitialAd.show();
                            mInterstitialAd.setAdListener(new AdListener() {
                                public void onAdClosed() {
                                    AdRequest adRequest = new AdRequest.Builder()
                                            .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                                            .build();
                                    mInterstitialAd.loadAd(adRequest);
                                    Intent calc = new Intent(Calculator.this, Calculator.class);
                                    //calc.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
                                    //getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                                    startActivity(calc);
                                }
                            });
                        } else {
                            Intent calc = new Intent(Calculator.this, Calculator.class);
                            //calc.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            //getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                            startActivity(calc);
                        }
                        break;
                    case 1:
                        fragment = new UnitsFragment();
                        FragmentManager unitfragment = getSupportFragmentManager();
                        unitfragment.beginTransaction().replace(R.id.content_frame,fragment).commit();
                        if (mInterstitialAd.isLoaded()) {
                            mInterstitialAd.show();
                            mInterstitialAd.setAdListener(new AdListener() {
                                public void onAdClosed() {
                                    AdRequest adRequest = new AdRequest.Builder()
                                            .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                                            .build();
                                    mInterstitialAd.loadAd(adRequest);
                                    //getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
                                    mDrawerLayout.closeDrawers();
                                }
                            });
                        } else  {
                            mDrawerLayout.closeDrawers();
                        }
                        break;
                    case 2:
                        fragment = new CurrencyFragment();
                        FragmentManager currencyfragment = getSupportFragmentManager();
                        currencyfragment.beginTransaction().replace(R.id.content_frame,fragment).commit();
                        if (mInterstitialAd.isLoaded()) {
                            mInterstitialAd.show();
                            mInterstitialAd.setAdListener(new AdListener() {
                                public void onAdClosed() {
                                    AdRequest adRequest = new AdRequest.Builder()
                                            .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                                            .build();
                                    mInterstitialAd.loadAd(adRequest);
                                    mDrawerLayout.closeDrawers();
                                }
                            });
                        } else {
                            mDrawerLayout.closeDrawers();
                        }
                        break;
                    case 3:
                        fragment = new DateFragment();