package org.thosp.yourlocalweather.utils;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.content.ContextCompat;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.WindowManager;

import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;

import org.thosp.yourlocalweather.R;
import org.thosp.yourlocalweather.model.DetailedWeatherForecast;
import org.thosp.yourlocalweather.model.WidgetSettingsDbHelper;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;


public class GraphUtils {

    private static Map<Integer, Bitmap> combinedGraphs = new HashMap<>();

    public static Bitmap getCombinedChart(Context context,
                                          int widgetId,
                                          Float heightMultiplier,
                                          List<DetailedWeatherForecast> weatherForecastList,
                                          long locationId,
                                          Locale locale) {

        if (combinedGraphs.get(widgetId) != null) {
            return combinedGraphs.get(widgetId);
        }

        WidgetSettingsDbHelper widgetSettingsDbHelper = WidgetSettingsDbHelper.getInstance(context);
        Boolean showLegend = widgetSettingsDbHelper.getParamBoolean(widgetId, "combinedGraphShowLegend");

        if (showLegend == null) {
            showLegend = true;
        }

        int[] size = getWidgetSize(context, widgetId);
        int width = size[0];
        int height;
        if (heightMultiplier == null) {
            height = size[1];
        } else {
            height = (int) (width * heightMultiplier);
        }

        int yAxisValues = 4;
        if (height > 800) {
            yAxisValues += 6;
        } else if (height > 700) {
            yAxisValues += 4;
        } else if (height > 500) {
            yAxisValues += 2;
        }

        CombinedChart combinedChart = generateCombinedGraph(context,
                                    null,
                                                            getCombinedGraphValuesFromSettings(context, widgetSettingsDbHelper, widgetId),
                                                            weatherForecastList,
                                                            locationId,
                                                            locale,
                                                            18f,
                                                            yAxisValues,
                                                            0,
                                                            AppPreference.getTextColor(context),
                                                            AppPreference.getWidgetBackgroundColor(context),
                                                            AppPreference.getWidgetGraphGridColor(context),
                                                            showLegend);

        combinedChart.setBackgroundColor(ContextCompat.getColor(context,
                R.color.widget_transparentTheme_colorBackground));

        int bitmapHeight = height;

        if (!showLegend) {
            bitmapHeight += 20;
        }

        Bitmap.Config bitmapConfig = Bitmap.Config.ARGB_8888;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            bitmapConfig = Bitmap.Config.RGBA_F16;
        }
        Bitmap combinedChartBitmap = Bitmap.createBitmap(width, bitmapHeight, bitmapConfig);
        Canvas combinedChartCanvas = new Canvas(combinedChartBitmap);
        combinedChart.layout(0, 0, width, height);
        combinedChart.draw(combinedChartCanvas);
        combinedGraphs.put(widgetId, combinedChartBitmap);
        return combinedChartBitmap;
    }

    protected static int[] getWidgetSize(Context context, int appWidgetId) {
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(
                context.getApplicationContext());

        AppWidgetProviderInfo providerInfo = appWidgetManager.getAppWidgetInfo(appWidgetId);

        int mWidgetLandWidth = providerInfo.minWidth;
        int mWidgetPortHeight = providerInfo.minHeight;
        int mWidgetPortWidth = providerInfo.minWidth;
        int mWidgetLandHeight = providerInfo.minHeight;

        Bundle mAppWidgetOptions = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            mAppWidgetOptions = appWidgetManager.getAppWidgetOptions(appWidgetId);
        }

        if (mAppWidgetOptions != null
                && mAppWidgetOptions
                .getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) > 0) {

            mWidgetPortWidth = mAppWidgetOptions
                    .getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
            mWidgetLandWidth = mAppWidgetOptions
                    .getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
            mWidgetLandHeight = mAppWidgetOptions
                    .getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
            mWidgetPortHeight = mAppWidgetOptions
                    .getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
        } else {
            mWidgetLandWidth = providerInfo.minWidth;
            mWidgetPortHeight = providerInfo.minHeight;
            mWidgetPortWidth = providerInfo.minWidth;
            mWidgetLandHeight = providerInfo.minHeight;
        }

        int mWidgetWidthPerOrientation = mWidgetPortWidth;
        int mWidgetHeightPerOrientation = mWidgetPortHeight;
        if (!isPortrait(context)) {
            mWidgetWidthPerOrientation = mWidgetLandWidth;
            mWidgetHeightPerOrientation = mWidgetLandHeight;
        }
        int[] size = new int[2];
        if (AppPreference.isWidgetGraphNativeScaled(context)) {
            size[0] = mWidgetWidthPerOrientation;
            size[1] = mWidgetHeightPerOrientation;
            return size;
        }
        size[0] = dipToPixels(context, mWidgetWidthPerOrientation);
        size[1] = dipToPixels(context, mWidgetHeightPerOrientation);
        return size;
    }

    public static Set<Integer> getCombinedGraphValuesFromSettings(Context context, WidgetSettingsDbHelper widgetSettingsDbHelper, int widgetId) {
        Set<Integer> combinedGraphValues = new HashSet<>();

        String storedGraphValues = widgetSettingsDbHelper.getParamString(widgetId, "combinedGraphValues");
        if ((storedGraphValues == null) || !storedGraphValues.contains(",")) {
            combinedGraphValues = AppPreference.getCombinedGraphValues(context);
            StringBuilder valuesToStore = new StringBuilder();
            for (int selectedValue: combinedGraphValues) {
                valuesToStore.append(selectedValue);
                valuesToStore.append(",");
            }
            widgetSettingsDbHelper.saveParamString(widgetId, "combinedGraphValues", valuesToStore.toString());
        } else {
            String[] values = storedGraphValues.split(",");
            for (String value: values) {
                int intValue;
                try {
                    intValue = Integer.parseInt(value);
                    combinedGraphValues.add(intValue);
                } catch (Exception e) {
                    //do nothing, just continue
                }
            }
        }

        return combinedGraphValues;
    }

    public static int dipToPixels(Context context, int dipValue) {
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
    }

    private static boolean isPortrait (Context cx) {
        Display d = ((WindowManager) cx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        if (d.getWidth() == d.getHeight()) {
            return false;
        } else {
            return d.getWidth() < d.getHeight();
        }
    }

    public static void invalidateGraph() {
        combinedGraphs = new HashMap<>();
    }

    public static CombinedChart generateCombinedGraph(Context context,
                                                      CombinedChart combinedChartFromLayout,
                                                      Set<Integer> combinedGraphValues,
                                                      List<DetailedWeatherForecast> weatherForecastList,
                                                      long locationId,
                                                      Locale locale,
                                                      Float textSize,
                                                      Integer yAxisValues,
                                                      int yAxisFractionalDigits,
                                                      int textColorId,
                                                      int backgroundColorId,
                                                      AppPreference.GraphGridColors gridColorId,
                                                      boolean showLegend) {

        CustomValueFormatter mValueFormatter = new CustomValueFormatter(locale);

        boolean pressure = false;
        boolean rainsnow = false;
        boolean wind = false;
        boolean temperature = false;
        CombinedGraph leftYaxis = null;
        CombinedGraph rightYaxis = null;

        if (combinedGraphValues.contains(0)) {
            temperature = true;
            leftYaxis = CombinedGraph.TEMPERATURE;
        }
        if (combinedGraphValues.contains(2)) {
            wind = true;
            if (leftYaxis == null) {
                leftYaxis = CombinedGraph.WIND;
            } else {
                rightYaxis = CombinedGraph.WIND;
            }
        }
        if (combinedGraphValues.contains(3)) {
            pressure = true;
            if (leftYaxis == null) {
                leftYaxis = CombinedGraph.PRESSURE;
            } else {
                rightYaxis = CombinedGraph.PRESSURE;
            }
        }
        if (combinedGraphValues.contains(1)) {
            rainsnow = true;
            if (leftYaxis == null) {
                leftYaxis = CombinedGraph.RAINSNOW;
            } else if (rightYaxis == null) {
                rightYaxis = CombinedGraph.RAINSNOW;
            }
        }

        CombinedChart combinedChart = (combinedChartFromLayout != null) ? combinedChartFromLayout : new CombinedChart(context);
        Description graphDescription = new Description();
        graphDescription.setText("");
        combinedChart.setDescription(graphDescription);
        combinedChart.setDrawGridBackground(false);
        combinedChart.setTouchEnabled(true);
        combinedChart.setDragEnabled(true);
        combinedChart.setMaxHighlightDistance(300);
        combinedChart.setPinchZoom(true);
        combinedChart.getLegend().setEnabled(showLegend);
        combinedChart.getLegend().setTextColor(textColorId);
        combinedChart.getLegend().setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
        combinedChart.getLegend().setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
        if (textSize != null) {
            combinedChart.getLegend().setTextSize(textSize);
        }
        combinedChart.setBackgroundColor(backgroundColorId);
        combinedChart.setGridBackgroundColor(textColorId);

        setupXAxis(combinedChart.getXAxis(), weatherForecastList, textColorId, textSize, gridColorId, locale);

        int temperatureListSize = weatherForecastList.size();
        double[] temperatures = new double[temperatureListSize];
        double minTemperatureValue = Double.MAX_VALUE;
        double maxTemperatureValue = Double.MIN_VALUE;
        for (int i = 0; i < temperatureListSize; i++) {
            double temperatureValue = TemperatureUtil.getTemperature(context, weatherForecastList.get(i));
            temperatures[i] = temperatureValue;
            if (temperatureValue < minTemperatureValue) {
                minTemperatureValue = temperatureValue;
            }
            if (temperatureValue > maxTemperatureValue) {
                maxTemperatureValue = temperatureValue;
            }
        }

        maxTemperatureValue += 1;
        minTemperatureValue -= 1;

        List<Entry> temperatureEntries = new ArrayList<>();
        int entryCounter = 0;
        for (double temperatureForEntry: temperatures) {
            temperatureEntries.add(new Entry(
                    entryCounter++,
                    (float) temperatureForEntry));
        }

        LineDataSet set = new LineDataSet(temperatureEntries, context.getString(R.string.graph_temperature_day_label));
        set.setMode(LineDataSet.Mode.CUBIC_BEZIER);
        set.setCubicIntensity(0.2f);
        set.setDrawCircles(false);
        set.setLineWidth(2f);
        set.setValueTextSize(12f);
        set.setDrawValues(false);
        set.setColor(Color.parseColor("#E84E40"));
        set.setHighlightEnabled(false);
        set.setValueFormatter(mValueFormatter);
        set.setValueTextColor(textColorId);


        double valueShifter = 0;
        String temperatureUnitsFromPreferences = PreferenceManager.getDefaultSharedPreferences(context).getString(
                Constants.KEY_PREF_TEMPERATURE_UNITS, "celsius");
        if (temperatureUnitsFromPreferences.contains("fahrenheit")) {
            if (combinedGraphValues.contains(1)) {
                valueShifter = 0;
                minTemperatureValue = 0;
            } else {
                valueShifter = 32;
            }
        }

        double multiplier;
        String unitsFromPreferences = PreferenceManager.getDefaultSharedPreferences(context).getString(
                Constants.KEY_PREF_PRESSURE_UNITS, "hpa");
        switch (unitsFromPreferences) {
            case "inhg": multiplier = 50; break;
            default: multiplier = 1;
        }

        int pressuresSize = weatherForecastList.size();
        double[] pressures = new double[pressuresSize];
        double minPressureValue = Double.MAX_VALUE;
        double maxPressureValue = Double.MIN_VALUE;
        for (int i = 0; i < pressuresSize; i++) {
            PressureWithUnit pressureWithUnit = AppPreference.getPressureWithUnit(
                    context,
                    weatherForecastList.get(i).getPressure(),
                    locale);
            double pressureValue = multiplier * pressureWithUnit.getPressure();
            pressures[i] = pressureValue + valueShifter;
            if (pressureValue < minPressureValue) {
                minPressureValue = pressureValue;
            }
            if (pressureValue > maxPressureValue) {
                maxPressureValue = pressureValue;
            }
        }

        List<Entry> pressureEntries = new ArrayList<>();
        entryCounter = 0;
        for (double pressureForEntry: pressures) {
            pressureEntries.add(new Entry(
                    entryCounter++,
                    (float) pressureForEntry));
        }

        double negativeValue = 0 - minTemperatureValue;
        if (negativeValue > 0) {
            minPressureValue = minPressureValue - negativeValue;
        }

        LineDataSet pressureSet = new LineDataSet(pressureEntries, context.getString(R.string.graph_pressure_label));
        pressureSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
        pressureSet.setCubicIntensity(0.2f);
        pressureSet.setDrawCircles(false);
        pressureSet.setLineWidth(2f);
        pressureSet.setValueTextSize(12f);
        pressureSet.setDrawValues(false);
        pressureSet.setColor(Color.parseColor("#20cb02"));
        pressureSet.setHighlightEnabled(false);
        pressureSet.setValueFormatter(mValueFormatter);
        pressureSet.setValueTextColor(textColorId);
        if (rightYaxis == CombinedGraph.PRESSURE) {
            pressureSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
        }

        List<BarEntry> rainEntries = new ArrayList<>();
        int rainSnowSize = weatherForecastList.size();
        float[] rains = new float[rainSnowSize];
        float[] snows = new float[rainSnowSize];
        double minRainSnowValue = Double.MAX_VALUE;
        double maxRainSnowValue = Double.MIN_VALUE;
        boolean isRain = false;
        boolean isSnow = false;
        double rainSnowmultiplier = 1;
        for (int i = 0; i < weatherForecastList.size(); i++) {
            DetailedWeatherForecast detailedWeatherForecast = weatherForecastList.get(i);
            if ((leftYaxis != CombinedGraph.RAINSNOW) && (rightYaxis != CombinedGraph.RAINSNOW)) {
                rainSnowmultiplier = 10;
            }
            double rainValue = rainSnowmultiplier * AppPreference.getRainOrSnow(
                    context, detailedWeatherForecast.getRain());
            if (!isRain && (rainValue > 0)) {
                isRain = true;
            }
            double snowValue = rainSnowmultiplier * AppPreference.getRainOrSnow(
                    context, detailedWeatherForecast.getSnow());
            if (!isSnow && (snowValue > 0)) {
                isSnow = true;
            }
            double rainsnowValue = snowValue + rainValue;
            if (rainsnowValue < minRainSnowValue) {
                minRainSnowValue = rainsnowValue;
            }
            if (rainsnowValue > maxRainSnowValue) {
                maxRainSnowValue = rainsnowValue;
            }
            rains[i] = (float) (valueShifter + rainValue);
            snows[i] = (float) (valueShifter + snowValue);
        }

        boolean isRainSnowVector = isRain && isSnow;
        for (int i = 0; i < weatherForecastList.size(); i++) {
            if (isRainSnowVector) {
                float[] rainsnowBarData = new float[2];
                rainsnowBarData[0] = rains[i];
                rainsnowBarData[1] = snows[i];
                rainEntries.add(new BarEntry(
                        i,
                        rainsnowBarData));
            } else if (isRain){
                rainEntries.add(new BarEntry(
                        i,
                        rains[i]));
            } else if (isSnow){
                rainEntries.add(new BarEntry(
                        i,
                        snows[i]));
            } else {
                rainEntries.add(new BarEntry(
                        i,
                        rains[i]));
            }
        }

        String[] rainSnowLabels = getRainSnowLabelForCombinedGraph(context, locale, rainSnowmultiplier, isRain, isSnow);
        boolean twoBars = rainSnowLabels.length > 1;
        BarDataSet rainSet = new BarDataSet(rainEntries, (twoBars)? null : rainSnowLabels[0]);
        rainSet.setValueTextSize(12f);
        rainSet.setDrawValues(false);
        rainSet.setHighlightEnabled(false);
        rainSet.setValueFormatter(mValueFormatter);
        rainSet.setValueTextColor(textColorId);
        if (twoBars) {
            rainSet.setColors(Color.parseColor("#5677FC"), Color.parseColor("#aaaaff"));
        } else if (isSnow) {
            rainSet.setColor(Color.parseColor("#ccd6fe"));
        } else {
            rainSet.setColor(Color.parseColor("#5677FC"));
        }
        if (twoBars) {
            rainSet.setStackLabels(rainSnowLabels);
        }
        if (rightYaxis == CombinedGraph.RAINSNOW) {
            rainSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
        }

        List<Entry> windEntries = new ArrayList<>();
        int windSize = weatherForecastList.size();
        double minWindValue = Double.MAX_VALUE;
        double maxWindValue = Double.MIN_VALUE;
        for (int i = 0; i < windSize; i++) {
            double windSpeed = AppPreference.getWind(context, weatherForecastList.get(i).getWindSpeed());
            if (windSpeed < minWindValue) {
                minWindValue = windSpeed;
            }
            if (windSpeed > maxWindValue) {
                maxWindValue = windSpeed;
            }
            windEntries.add(new Entry(i, (float) (windSpeed + valueShifter)));
        }

        LineDataSet windSet = new LineDataSet(windEntries, context.getString(R.string.graph_wind_label));
        windSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
        windSet.setCubicIntensity(0.2f);
        windSet.setDrawCircles(false);
        windSet.setLineWidth(2f);
        windSet.setValueTextSize(12f);
        windSet.setDrawValues(false);
        windSet.setColor(Color.parseColor("#00BCD4"));
        windSet.setHighlightEnabled(false);
        windSet.setValueFormatter(mValueFormatter);
        windSet.setValueTextColor(textColorId);
        if (rightYaxis == CombinedGraph.WIND) {
            windSet.setAxisDependency(YAxis.AxisDependency.RIGHT);
        }

        double pressureScale = 0;
        if (pressure) {
            pressureScale = (maxPressureValue - minPressureValue);
        }
        if (rainsnow && (rightYaxis != CombinedGraph.RAINSNOW)) {
            pressureScale = (maxRainSnowValue - minRainSnowValue) + 2;
        }

        double maxValueOnGraph;

        if (maxTemperatureValue > pressureScale) {
            maxValueOnGraph = maxTemperatureValue;
        } else {
            maxValueOnGraph = pressureScale + 1;
        }


        YAxis yLeft = combinedChart.getAxisLeft();
        yLeft.setEnabled(true);
        yLeft.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
        yLeft.setDrawAxisLine(false);
        yLeft.setDrawGridLines(true);
        yLeft.enableGridDashedLine(5f, 10f, 0f);
        yLeft.setTextColor(textColorId);
        yLeft.setGridColor(gridColorId.getMainGridColor());
        yLeft.setZeroLineWidth(20f);
        if (textSize != null) {
            yLeft.setTextSize(textSize);
        }
        yLeft.setXOffset(15);
        if (yAxisValues != null) {
            yLeft.setLabelCount(yAxisValues, true);
        }
        if (leftYaxis == CombinedGraph.TEMPERATURE) {
            yLeft.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, TemperatureUtil.getTemperatureUnit(context)));
            double axisMaximum = Math.ceil(maxValueOnGraph);
            double axisMinimum = Math.floor(minTemperatureValue);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yLeft.setAxisMaximum((float) (axisMaximum));
            yLeft.setAxisMinimum((float) (axisMinimum));
        } else if (leftYaxis == CombinedGraph.WIND) {
            double axisMaximum = Math.ceil((maxWindValue + 1));
            double axisMinimum = Math.floor(minWindValue);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yLeft.setAxisMaximum((float) (axisMaximum));
            yLeft.setAxisMinimum((float) (axisMinimum));
            yLeft.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, AppPreference.getWindUnit(context)));
        } else if (leftYaxis == CombinedGraph.PRESSURE) {
            double axisMaximum = Math.ceil(((maxPressureValue + 2) / multiplier));
            double axisMinimum = Math.floor(minPressureValue / multiplier);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yLeft.setAxisMaximum((float) (axisMaximum));
            yLeft.setAxisMinimum((float) (axisMinimum));
            yLeft.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, AppPreference.getPressureUnit(context)));
        } else if (leftYaxis == CombinedGraph.RAINSNOW) {
            double axisMaximum = Math.ceil((maxRainSnowValue + 1));
            double axisMinimum = Math.floor(minRainSnowValue);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yLeft.setAxisMaximum((float) (axisMaximum));
            yLeft.setAxisMinimum((float) (axisMinimum));
            yLeft.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, context.getString(AppPreference.getRainOrSnowUnit(context))));
        }
        LimitLine zerolimitLine = new LimitLine(0);
        zerolimitLine.setLineColor(gridColorId.getMainGridColor());
        zerolimitLine.setLineWidth(0.5f);
        yLeft.addLimitLine(zerolimitLine);

        YAxis yRight = combinedChart.getAxisRight();
        yRight.setEnabled(true);
        yRight.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
        yRight.setDrawAxisLine(false);
        yRight.setDrawGridLines(true);
        yRight.enableGridDashedLine(5f, 10f, 0f);
        yRight.setTextColor(textColorId);
        yRight.setGridColor(gridColorId.getMainGridColor());
        yRight.setZeroLineWidth(20f);
        if (textSize != null) {
            yRight.setTextSize(textSize);
        }
        yRight.setXOffset(15);
        if (yAxisValues != null) {
            yRight.setLabelCount(yAxisValues, true);
        }
        if (rightYaxis == CombinedGraph.WIND) {
            double axisMaximum = Math.ceil((maxWindValue + 1));
            double axisMinimum = Math.floor(minWindValue);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yRight.setAxisMaximum((float) (axisMaximum));
            yRight.setAxisMinimum((float) (axisMinimum));
            yRight.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, AppPreference.getWindUnit(context)));
        } else if (rightYaxis == CombinedGraph.PRESSURE) {
            double axisMaximum = Math.ceil(((maxPressureValue + 1) / multiplier));
            double axisMinimum = Math.floor(minPressureValue / multiplier);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yRight.setAxisMaximum((float) (axisMaximum));
            yRight.setAxisMinimum((float) (axisMinimum));
            yRight.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, AppPreference.getPressureUnit(context)));
        } else if (rightYaxis == CombinedGraph.RAINSNOW) {
            double axisMaximum = Math.ceil((maxRainSnowValue + 1));
            double axisMinimum = Math.floor(minRainSnowValue);
            if (yAxisValues != null) {
                int restForRange = (yAxisValues - 1) - (((int) (axisMaximum - axisMinimum)) % (yAxisValues - 1));
                int halfOfTHeDifference = restForRange / 2;
                int restOfTheDifference = restForRange % 2;
                axisMaximum += halfOfTHeDifference + restOfTheDifference;
                axisMinimum -= halfOfTHeDifference;
            }
            yRight.setAxisMaximum((float) (axisMaximum));
            yRight.setAxisMinimum((float) (axisMinimum));
            yRight.setValueFormatter(new YAxisValueFormatter(locale, yAxisFractionalDigits, context.getString(AppPreference.getRainOrSnowUnit(context))));
        }
        if (rightYaxis == null) {
            yRight.setEnabled(false);
        } else {
            yRight.setEnabled(true);
        }

        combinedChart.clear();
        LineData lineData = new LineData();
        if (temperature) {
            lineData.addDataSet(set);
        }
        if (pressure) {
            lineData.addDataSet(pressureSet);
        }
        if (wind) {
            lineData.addDataSet(windSet);
        }
        CombinedData data = new CombinedData();
        data.setData(lineData);
        if (rainsnow) {
            BarData rainData = new BarData();
            rainData.addDataSet(rainSet);
            data.setData(rainData);
        } else {
            BarData rainData = new BarData();
            data.setData(rainData);
        }
        combinedChart.setData(data);
        combinedChart.invalidate();
        return combinedChart;
    }

    public static void setupXAxis(XAxis x,
                                  List<DetailedWeatherForecast> weatherForecastList,
                                  int textColorId,
                                  Float textSize,
                                  AppPreference.GraphGridColors gridColor,
                                  Locale locale) {
        x.removeAllLimitLines();
        Map<Integer, Long> hourIndexes = new HashMap<>();

        int lastDayOflimitLine = 0;
        for (int i = 0; i < weatherForecastList.size(); i++) {
            hourIndexes.put(i, weatherForecastList.get(i).getDateTime());
            Calendar cal = Calendar.getInstance();
            cal.setTimeInMillis(weatherForecastList.get(i).getDateTime() * 1000);
            if (cal.get(Calendar.DAY_OF_YEAR) != lastDayOflimitLine) {
                Calendar calOfPreviousRecord = Calendar.getInstance();
                int previousRecordHour = 24;
                if (i > 0) {
                    calOfPreviousRecord.setTimeInMillis(weatherForecastList.get(i - 1).getDateTime() * 1000);
                    previousRecordHour = calOfPreviousRecord.get(Calendar.HOUR_OF_DAY);
                }
                int currentHour = cal.get(Calendar.HOUR_OF_DAY);
                float timeSpan = (24 - previousRecordHour) + currentHour;
                float dayLine = currentHour / timeSpan;
                float midnight = i - dayLine;
                float hour6 = midnight + (6 / timeSpan);
                float hour12 = midnight + (12 / timeSpan);
                float hour18 = midnight + (18 / timeSpan);
                LimitLine limitLine = new LimitLine(midnight);
                limitLine.setLineColor(gridColor.getMainGridColor());
                limitLine.setLineWidth(0.5f);
                x.addLimitLine(limitLine);
                /*LimitLine limitLine6 = new LimitLine(hour6, "");
                limitLine6.setLineColor(Color.LTGRAY);
                limitLine6.setLineWidth(0.5f);
                x.addLimitLine(limitLine6);*/
                LimitLine limitLine12 = new LimitLine(hour12);
                limitLine12.setLineColor(gridColor.getSecondaryGridColor());
                limitLine12.setLineWidth(0.5f);
                x.addLimitLine(limitLine12);
                /*LimitLine limitLine18 = new LimitLine(hour18, "");
                limitLine18.setLineColor(Color.LTGRAY);
                limitLine18.setLineWidth(0.5f);
                x.addLimitLine(limitLine18);*/
                lastDayOflimitLine = cal.get(Calendar.DAY_OF_YEAR);
            }
        }

        x.setEnabled(true);
        x.setPosition(XAxis.XAxisPosition.BOTTOM);
        x.setDrawGridLines(false);
        x.setLabelCount(25, true);
        x.setTextColor(textColorId);
        x.setValueFormatter(new XAxisValueFormatter(hourIndexes, locale));
        x.setDrawLimitLinesBehindData(true);

        if (textSize != null) {
            x.setTextSize(textSize);
        }
    }

    public static String[] getRainSnowLabelForCombinedGraph(Context context, Locale locale, double multiplier, boolean isRain, boolean isSnow) {
        NumberFormat decimalFormat = NumberFormat.getNumberInstance(locale);
        decimalFormat.setMaximumFractionDigits(1);
        decimalFormat.setMinimumFractionDigits(1);

        int resultSize = 1;
        if (isRain && isSnow) {
            resultSize = 2;
        }
        String[] result = new String[resultSize];
        StringBuilder rainLabelBuilder = new StringBuilder();
        StringBuilder snowLabelBuilder = new StringBuilder();
        if (isRain) {
            rainLabelBuilder.append(context.getString(R.string.graph_rain_label));
        }
        if (isSnow) {
            snowLabelBuilder.append(context.getString(R.string.graph_snow_label));
        }
        if (!isRain && !isSnow) {
            rainLabelBuilder.append(context.getString(R.string.graph_rain_label));
        }

        StringBuilder addInfoLabelBuilder;
        if (isRain && isSnow) {
            addInfoLabelBuilder = snowLabelBuilder;
        } else if (isRain) {
            addInfoLabelBuilder = rainLabelBuilder;
        } else if (isSnow) {
            addInfoLabelBuilder = snowLabelBuilder;
        } else {
            addInfoLabelBuilder = rainLabelBuilder;
        }

        if (multiplier != 1.0) {
            addInfoLabelBuilder.append(" (*");
            addInfoLabelBuilder.append(decimalFormat.format(1 / multiplier));
            addInfoLabelBuilder.append(" ");
            addInfoLabelBuilder.append(context.getString(AppPreference.getRainOrSnowUnit(context)));
            addInfoLabelBuilder.append(" on ");
            addInfoLabelBuilder.append(TemperatureUtil.getTemperatureUnit(context));
            addInfoLabelBuilder.append(")");
        }
        if (isRain && isSnow) {
            result[0] = rainLabelBuilder.toString();
            result[1] = snowLabelBuilder.toString();
        } else if (isRain) {
            result[0] = rainLabelBuilder.toString();
        } else if (isSnow){
            result[0] = snowLabelBuilder.toString();
        } else {
            result[0] = rainLabelBuilder.toString();
        }
        return result;
    }
}