import React from 'react';
import { View, StyleSheet, BackHandler, Dimensions, TouchableOpacity, NativeEventEmitter } from 'react-native';
import Text from 'text/Text';
import Form, {FormHeader, FormBody} from 'ui/Form';
import Textbox from 'fields/Textbox';
import Picker from 'fields/Picker';
import CheckBox from 'fields/CheckBox';
import ListPicker from 'fields/ListPicker';
import ButtonPlus from 'buttons/ButtonPlus';
import ButtonClose from 'buttons/ButtonClose';
import IconArrowRight from 'icons/IconArrowRight';
import IconArrowUpBorderThin from 'icons/IconArrowUpBorderThin';
import ToolTip from 'tooltip/Top';
import DbTasks from 'db/DbTasks';
import DbCharts from 'db/DbCharts';
import LineChart from 'charts/LineChart';
import TimeRange from 'charts/TimeRange';
import Statistic from 'charts/Statistic';
import CheckList from 'charts/CheckList';
import Currencies from 'utility/Currencies';
import GetDate from 'utility/Date';


export default class ChartScreen extends React.Component {
    constructor(props) {
        super(props);

        let dbTasks = new DbTasks();
        let date = GetDate();
        let startdate = this.props.navigation.getParam('datestart', date.setDate(date.getDate() - 14));
        let days = this.props.navigation.getParam('days', 14);

        this.state = {
            chart: {
                id:null,
                name:'',
                type:1,
                style:null,
                outline:null,
                featured:false,
                filters:false,
                offset:0,
                index:0,
                sources:[],
                startdate: this.na
            },
            datestart:startdate,
            days:days,
            chartItem:[], //rendered chart
            sourcesList:[], //rendered
            tasks:dbTasks.GetList(),
            taskForm:{
                height:250,
                inputsOffset:0
            },
            title:'',
            screenTitle:'',
            ButtonAddShow: true,
            ButtonInTitleBar: false,
            visibleHeight:0,
            contentOffset:0,
            edited:false,
            layoutWidth:0,
            update:1
        }

        this.chartType = [
            {label:'Line Graph', value:1, show:true, hasOffset:true, color:true},
            {label:'Time Ranges', value:2, show:true, hasOffset:true, color:true},
            {label:'Scatter Plot', value:3, show:false, hasOffset:true, color:true},
            {label:'Pie Chart', value:4, show:false, hasOffset:true, color:true},
            {label:'Statistic: Count', value:5, show:true, hasOffset:true},
            {label:'Statistic: Sum', value:6, show:true, hasOffset:true},
            {label:'Statistic: Average', value:7, show:true, hasOffset:true},
            {label:'Statistic: Percentage', value:8, show:true, hasOffset:true, color:true,
                styles:[
                    {label:'Text Only', value:1},
                    {label:'Text Below Pie Chart', value:2},
                    {label:'Text Next To Pie Chart', value:3},
                    {label:'Text Inside Pie Chart', value:4},
                    {label:'Pie Chart Only', value:5},
                ]
            },
            {label:'Check List', value:9, show:true, defaultInput:{
                offset:1
            }}, //, requiredInputs:[6]},
        ];

        //update layout width
        const {width} = Dimensions.get('window');
        this.state.layoutWidth = width;

        //create emitter
        this.updateEmitter = new NativeEventEmitter();

        //bind methods
        this.hardwareBackPress = this.hardwareBackPress.bind(this);
        this.onLayout = this.onLayout.bind(this);
        this.loadToolbar = this.loadToolbar.bind(this);
        this.onChartNameChange = this.onChartNameChange.bind(this);
        this.onChartTypeChange = this.onChartTypeChange.bind(this);
        this.onChartDateOffsetChange = this.onChartDateOffsetChange.bind(this);
        this.onChartStyleChange = this.onChartStyleChange.bind(this);
        this.onFeaturedChange = this.onFeaturedChange.bind(this);
        this.onFiltersChange = this.onFiltersChange.bind(this);
        this.onStatisticOutlineChange = this.onStatisticOutlineChange.bind(this);
        this.onPressAddInput = this.onPressAddInput.bind(this);
        this.onPressButtonSave = this.onPressButtonSave.bind(this);
        this.selectDataSource = this.selectDataSource.bind(this);
        this.renderSources = this.renderSources.bind(this);
        this.ColorBox = this.ColorBox.bind(this);
        this.removeSource = this.removeSource.bind(this);
        this.onChangeSourceInput = this.onChangeSourceInput.bind(this);
        this.onChangeSourceLabel = this.onChangeSourceLabel.bind(this);
        this.onChangeSourceOffset = this.onChangeSourceOffset.bind(this);
        this.onChangeSourceColor = this.onChangeSourceColor.bind(this);
        this.onShowColorModal = this.onShowColorModal.bind(this);
        this.onChangeConditionType = this.onChangeConditionType.bind(this);
        this.validateForm = this.validateForm.bind(this);
        this.onPressAddFilter = this.onPressAddFilter.bind(this);
        this.selectFilterInput = this.selectFilterInput.bind(this);
        this.onChangeFilterInput = this.onChangeFilterInput.bind(this);
        this.onChangeFilterOperator = this.onChangeFilterOperator.bind(this);
        this.onChangeFilterValue = this.onChangeFilterValue.bind(this);
        this.onChangeFilterListValue = this.onChangeFilterListValue.bind(this);
        this.removeFilter = this.removeFilter.bind(this);
    }

    // Component Events  //////////////////////////////////////////////////////////////////////////////////////
    componentWillMount(){
        BackHandler.addEventListener('hardwareBackPress', this.hardwareBackPress);
    }

    componentDidMount(){
        requestAnimationFrame(() => {
            let chart = null;
            let info = this.props.navigation.getParam('chart', null);
            let lists = {};
            if(info != null){
                //load existing chart
                chart = {
                    id: info.id,
                    name:info.name,
                    type: info.type,
                    style: info.style,
                    outline: info.outline,
                    featured: info.featured,
                    filters: info.filters,
                    offset: info.offset,
                    index: info.index,
                    sources: []
                }

                for(let x = 0; x < info.sources.length; x++){
                    const source = info.sources[x];
                    const task = source.task || global.realm.objects('Task').filtered('id = $0', source.taskId)[0];
                    const filters = source.filters != null ? source.filters.map(a => a) : [];
                    chart.sources.push({
                        id: source.id,
                        label: source.label,
                        style: source.style,
                        color: source.color,
                        taskId: source.taskId,
                        task: task,
                        inputId: source.inputId,
                        input: source.input,
                        offset: source.offset,
                        filters: filters
                    });
                    
                    //check filters for lists
                    for(let y = 0; y < filters.length; y++){
                        const filter = JSON.parse(filters[y]);
                        const input = task.inputs[task.inputs.map(a => a.id).indexOf(filter.inputId)];
                        if(input.type == 10){
                            //filter uses list
                            const listItem = global.realm.objects('ListItem').filtered('id = $0', filter.value)[0];
                            lists[listItem.id] = listItem.label;
                        }
                    }
                }
                this.setState({chart:chart, title:'Edit Chart', lists:lists}, () => {
                    this.renderSources();
                });
            }else{
                //load new chart
                this.setState({title:'New Chart'});
            }
            this.loadToolbar();
        });
    }

    componentWillUnmount () {
        BackHandler.removeEventListener('hardwareBackPress', this.hardwareBackPress);
    }

    hardwareBackPress() {
        const goback = this.props.navigation.getParam('goback', 'Analytics');
        global.navigate(this, goback);
        return true;
    }

    // Layout Changes ////////////////////////////////////////////////////////////////////////////////////////////////////

    onLayout(){
        const {width} = Dimensions.get('window');
        if(this.state.layoutWidth != width){
            this.setState({layoutWidth:width}, () => {
                this.renderSources();
            });
        }
    }

    // Load Toolbar ////////////////////////////////////////////////////////////////////////////////////////////////////

    loadToolbar(){
        global.updateToolbar({
            ...this.props, 
            screen:'Tasks',
            buttonAdd:true, 
            buttonRecord:true, 
            bottomFade:true, 
            hasTasks:true, 
            hasRecords:true,
            footerMessage: '',
            onAdd: global.proVersion == true ? this.showCreateChart : null
        });
    }

    // Chart Detail Changes //////////////////////////////////////////////////////////////////////////////////////////

    onChartNameChange(value){
        let chart = this.state.chart;
        chart.name = value;
        this.setState({chart:chart}, () => {
            this.renderChart();
            this.validateForm();
        });
    }

    onChartTypeChange(value){
        let chart = this.state.chart;
        chart.type = value;
        if(chart.type == 9 && (chart.offset == null || chart.offset == 0)){
            chart.offset = 1;
        }
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onChartDateOffsetChange(value){
        let chart = this.state.chart;
        chart.offset = value;
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onChartStyleChange(value){
        let chart = this.state.chart;
        chart.style = value;
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onFeaturedChange(checked){
        let chart = this.state.chart;
        chart.featured = checked;
        this.setState({chart:chart}, () => {
            this.validateForm();
        });
    }

    onFiltersChange(checked){
        let chart = this.state.chart;
        chart.filters = checked;
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onStatisticOutlineChange(checked){
        let chart = this.state.chart;
        chart.outline = checked;
        this.setState({
            chart:chart
        }, () => {
            this.renderChart();
            this.validateForm();
        });
    }

    // Select Data Source ///////////////////////////////////////////////////////////////////////////////////

    onPressAddInput(){
        let i  =0;
        let chartType = this.chartType[this.chartType.map(a => a.value).indexOf(this.state.chart.type)];
        global.Modal.setContent('Select Data Source', (
            <View style={this.styles.modalMenuContainer}>
                {this.state.tasks.map((task) => {
                    if(chartType.requiredInputs != null){
                        //check tasks for required input type
                        let found = false;
                        if(task.inputs == null || task.inputs.length == 0){return null;}
                        for(let x = 0; x < task.inputs.length; x++){
                            if(task.inputs.filter(input => input.type == chartType.requiredInputs[x]).length > 0){
                                found = true; break;
                            }
                        }
                        if(found == false){return null;}
                    }
                    i++;
                    return (
                        <TouchableOpacity key={i} onPress={() => {this.selectDataSource(task);}}>
                        <View style={this.styles.modalItemContainer}>
                            <Text style={this.styles.modalItemText}>{task.name}</Text>
                        </View>
                        </TouchableOpacity>
                    );
                })}
            </View>
        ));
        global.Modal.show();
    }

    selectDataSource(task){
        global.Modal.hide();
        let chart = this.state.chart;
        let chartType = this.chartType[this.chartType.map(a => a.value).indexOf(chart.type)];
        let defaultInput = {};
        if(chartType.defaultInput != null){
            defaultInput = chartType.defaultInput;
        }
        chart.sources.push({
            id: null,
            label:'',
            style: defaultInput.style || 1,
            color: (chart.sources.length + 1) % 8 || 8,
            taskId: task.id,
            task:task,
            inputId:null,
            input:null,
            offset:defaultInput.offset || null,
            filters:[],
            isnewkey:true
        });
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Render Sources List /////////////////////////////////////////////////////////////////////////////////

    renderSources(){
        let {width} = Dimensions.get('window');
        let chart = this.state.chart;
        let chartType = this.chartType[this.chartType.map(a => a.value).indexOf(chart.type)];
        let sourceType = 1; //1 = requires user to select source input, 2 = source input is unused
        let offsetType = 'Day';
        const w = width - 270;
        switch(chart.type){
            case 2: case 3: case 9:
                sourceType = 2;
                break;
        }
        switch(chart.offset){
            case 2: offsetType = 'Week'; break;
            case 3: offsetType = 'Month'; break;
            case 4: offsetType = 'Year'; break;
        }
        let list = chart.sources.map(source => {
            let i = 0;
            return (
            <View key={'src' + source.task.name} style={this.styles.sourceContainer}>
                <View style={this.styles.iconArrow}><IconArrowRight size="xsmall"/></View>
                <View style={this.styles.sourceHeader}>
                    <Text style={this.styles.sourceTitle}>{source.task.name}</Text>
                    <View style={this.styles.sourceColumn}>
                        {sourceType == 2 && chartType.color == true &&
                            <View style={[this.styles.colorBoxContainer, this.styles.padRight]}>
                                {this.ColorBox(source)}
                            </View>
                        }
                        <ButtonClose size="xxsmall" color={AppStyles.buttonLightColor} style={this.styles.sourceClose} onPress={() => {this.removeSource(source);}}/>
                    </View>
                </View>
                {sourceType == 1 && // Requires Input
                    <View style={this.styles.sourceBody}>
                        <View style={[this.styles.sourceInput, chartType.color == true ? {width:width - 80} : {width:'100%'}]}>
                            <Picker onValueChange={(value) => {this.onChangeSourceInput(source, value)}}
                                items={(chartType.requiredInputs ? [] : [{label:'No Input', value:null}]).concat(
                                    source.task.inputs.filter(a => chartType.requiredInputs ? chartType.requiredInputs.indexOf(a.type) >= 0 : [0, 5, 6, 7].indexOf(a.type) >= 0)
                                    .map(input => ({label:input.name, value:input.id}))
                                )}
                                defaultValue={null}
                                selectedValue={source.inputId}
                                borderColor={AppStyles.altFieldOutlineColor}
                            />
                        </View>
                        {chartType.color == true &&
                            <View style={[this.styles.colorBoxContainer, {marginTop:3}]}>
                                {this.ColorBox(source)}
                            </View>
                        }
                    </View>
                }
                {chart.type >= 5 && chart.type <= 8 && //Statistics
                    <View style={this.styles.sourceField}>
                        <Text style={this.styles.fieldLabel}>Label</Text>
                        <Textbox 
                            onChangeText={(value) => {this.onChangeSourceLabel(source, value)}} 
                            placeholder="optional"
                            defaultValue={source.label || ''}
                            maxLength={24}
                            borderColor={AppStyles.altFieldOutlineColor}
                            style={this.styles.fieldLabelTextbox}
                        />
                    </View>
                }
                {chart.offset != null && chart.offset > 0 && chart.type < 9 && //Not a Check List
                    <View style={this.styles.sourceNumericField}>
                        <Textbox 
                            onChangeText={(value) => {this.onChangeSourceOffset(source, value)}} 
                            placeholder="0"
                            defaultValue={source.offset != null && !isNaN(source.offset) ? source.offset.toString() : ''}
                            maxLength={4}
                            keyboardType="numeric"
                            style={[this.styles.fieldLabel, this.styles.fieldNumericInput]}
                            borderColor={AppStyles.altFieldOutlineColor}
                        />
                        <Text style={this.styles.fieldNumericLabel}>{offsetType} Offset</Text>
                    </View>
                }
                
                {chart.type == 9 && //Check List
                    <View>
                        <View style={this.styles.sourceInput}>
                            <View style={this.styles.row}>
                                <Text style={this.styles.fieldLabel}>Minimum Condition</Text>
                                <Text style={[this.styles.fieldLabel, {opacity:0.3}]}>to Complete Task</Text>
                            </View>
                            <Picker onValueChange={(value) => {this.onChangeConditionType(source, value)}}
                                items={[
                                    {label:'Number of Recorded Events', value:1},
                                    {label:'Total Recorded Time', value:2},
                                    source.task.inputs && source.task.inputs.length > 0 && source.task.inputs.filter(a => [0, 5, 6, 7].indexOf(a.type) >= 0).length > 0 ? 
                                    {label:'Sum of Recorded Data', value:3} : null
                                ]}
                                defaultValue={source.style}
                                selectedValue={source.style}
                                borderColor={AppStyles.altFieldOutlineColor}
                            />
                        </View>
                        {source.style == 1 && //Number of Recorded Events
                            <View style={this.styles.sourceNumericField}>
                                <Text style={this.styles.fieldNumericLabel}>Complete </Text>
                                <Textbox 
                                    onChangeText={(value) => {this.onChangeSourceOffset(source, value)}}
                                    defaultValue={source.offset != null && !isNaN(source.offset) ? source.offset.toString() : source.offset == null ? '1' : ''}
                                    maxLength={4}
                                    keyboardType="numeric"
                                    style={[this.styles.fieldLabel, this.styles.fieldNumericInput]}
                                    borderColor={AppStyles.altFieldOutlineColor}
                                />
                                <Text style={this.styles.fieldNumericLabel}>Time{source.offset != null ? source.offset > 1 ? 's' : '' : ''}</Text>
                            </View>
                        }
                        
                        {source.style == 2 && //Total Recorded Time
                            <View style={this.styles.sourceNumericField}>
                                <Textbox 
                                    onChangeText={(value) => {this.onChangeSourceOffset(source, value)}}
                                    defaultValue={source.offset != null && !isNaN(source.offset) ? source.offset.toString() : source.offset == null ? '1' : ''}
                                    maxLength={4}
                                    keyboardType="numeric"
                                    style={[this.styles.fieldLabel, this.styles.fieldNumericInput]}
                                    borderColor={AppStyles.altFieldOutlineColor}
                                />
                                <Text style={this.styles.fieldNumericLabel}>Minute{source.offset != null ? source.offset > 1 ? 's' : '' : ''}</Text>
                            </View>
                        }
                        
                        {source.style == 3 && //Sum of Recorded Data
                            <View>
                                <Text style={this.styles.fieldLabel}>Data Source</Text>
                                <View style={this.styles.sourceInput}>
                                    <Picker onValueChange={(value) => {this.onChangeSourceInput(source, value)}}
                                        items={source.task.inputs ? source.task.inputs.filter(a => [0, 5, 6, 7].indexOf(a.type) >= 0).map(input => ({label:input.name, value:input.id})) : []}
                                        defaultValue={null}
                                        selectedValue={source.inputId}
                                        borderColor={AppStyles.altFieldOutlineColor}
                                    />
                                </View>
                                <View style={this.styles.sourceNumericField}>
                                    <Text style={this.styles.fieldNumericLabel}>Minimum</Text>
                                    <Textbox 
                                        onChangeText={(value) => {this.onChangeSourceOffset(source, value)}}
                                        defaultValue={source.offset != null && !isNaN(source.offset) ? source.offset.toString() : source.offset == null ? '1' : ''}
                                        maxLength={10}
                                        keyboardType="numeric"
                                        style={[this.styles.fieldLabel, this.styles.fieldNumericInput]}
                                        borderColor={AppStyles.altFieldOutlineColor}
                                    />
                                    <Text style={this.styles.fieldNumericLabel}>Total of {source.input != null ? source.input.name : 'Unknown'}</Text>
                                </View>
                            </View>
                        }
                    </View>
                }

                
                { // Generate Filters for Data Source /////////////////////////////////////////////////////////////////////////////////////////////////////////
                    chart.filters == true && 
                    <View style={this.styles.filters}>
                        <View style={this.styles.filtersHead}>
                            <Text style={this.styles.fieldLabel}>Filters</Text>
                            <ButtonPlus style={this.styles.buttonAddFilter} color={AppStyles.color} size="xsmall" onPress={() => this.onPressAddFilter(source)} />
                        </View>
                        {source.filters != null ? source.filters.map(json => {
                            const filter = JSON.parse(json);
                            const input = source.task.inputs[source.task.inputs.map(a => a.id).indexOf(filter.inputId)];
                            let operators = this.getOperatorTypes(input.type);
                            let textfield = null;
                            const e = i;
                            i++;

                            //get textbox used for filter value
                            switch(input.type){
                                case 0: //Number
                                    textfield = (
                                        <Textbox 
                                            style={[this.styles.inputField, {width:w}]}
                                            placeholder={'10'}
                                            defaultValue={!isNaN(filter.value) ? filter.value : ''}
                                            keyboardType="numeric"
                                            returnKeyType={'done'} 
                                            blurOnSubmit={true}
                                            onChangeText={(text) => {this.onChangeFilterValue(source, e, text)}}
                                            maxLength={16}
                                            borderColor={AppStyles.altFieldOutlineColor}
                                        />
                                    );
                                    break;
                                case 5: //Currency
                                    const currency = Currencies.filter(c => c.value == input.option)[0];
                                    textfield = (
                                        <Textbox 
                                            currency={currency.symbol}
                                            style={[this.styles.inputField, {width:w}]}
                                            placeholder={'10'}
                                            defaultValue={filter.value || ''}
                                            keyboardType="numeric"
                                            returnKeyType={'done'} 
                                            blurOnSubmit={true}
                                            onChangeText={(text) => {this.onChangeFilterValue(source, e, text)}}
                                            maxLength={16}
                                            borderColor={AppStyles.altFieldOutlineColor}
                                        />
                                    );
                                    break;
                                case 1: case 8: case 9: //Text, Location, URL link
                                    textfield = (
                                        <Textbox 
                                            style={[this.styles.inputField, {width:w}]}
                                            placeholder={'text'}
                                            defaultValue={filter.value || ''}
                                            returnKeyType={'done'} 
                                            blurOnSubmit={true}
                                            onChangeText={(text) => {this.onChangeFilterValue(source, e, text)}}
                                            maxLength={25}
                                            borderColor={AppStyles.altFieldOutlineColor}
                                        />
                                    );
                                    break;
                                case 10: //List
                                    textfield = (
                                        <ListPicker
                                            selectedText={this.state.lists != null && this.state.lists[filter.value] != null ? this.state.lists[filter.value] : 'Select...'}
                                            onValueChange={(value) => {this.onChangeFilterListValue(source, e, value)}}
                                            style={[this.styles.listPicker, {width:w + (45 * AppStyles.vw)}]}
                                            borderColor={AppStyles.altFieldOutlineColor}
                                            listId={input.option}
                                            input={input}
                                            editable={false}
                                        />
                                    );
                                    break;
                            }

                            //generate filter
                            return (
                                <View key={e}>
                                    <View style={this.styles.filterArrow} pointerEvents="none">
                                        <IconArrowUpBorderThin
                                            color={AppStyles.color} 
                                            backgroundColor={AppStyles.altBackgroundColor} 
                                            size="smaller" viewWidth="32" viewHeight="32"
                                        />
                                    </View>
                                    <View style={this.styles.filterContainer}>
                                        <View style={this.styles.filterInputs}>
                                            <View style={this.styles.filterField}>
                                                <Picker onValueChange={(value) => {this.onChangeFilterInput(source, e, value)}}
                                                    items={source.task.inputs ? source.task.inputs.map(inp => ({label:inp.name, value:inp.id})) : []}
                                                    selectedValue={filter.inputId || null}
                                                    borderColor={AppStyles.altFieldOutlineColor}
                                                />
                                            </View>
                                            {input.type != 10 &&
                                                <View style={this.styles.filterField}>
                                                    <Picker onValueChange={(value) => {this.onChangeFilterOperator(source, e, value)}}
                                                        style={this.styles.operatorPicker}
                                                        items={operators}
                                                        selectedValue={filter.type != null ? parseInt(filter.type) : null}
                                                        borderColor={AppStyles.altFieldOutlineColor}
                                                    />
                                                </View>
                                            }
                                            <View style={this.styles.filterField}>{textfield}</View>
                                        </View>
                                        <ButtonClose size="xxxsmall" color={AppStyles.buttonLightColor} style={this.styles.filterClose} onPress={() => {this.removeFilter(source, e);}}/>
                                    </View>
                                </View>
                            );
                        }) : null}
                    </View>
                }
            </View>
        );});

        this.setState({sourcesList: list}, () => {
            this.renderChart();
        });
    }

    // Data Source Color Box ////////////////////////////////////////////////////////////////////////////
    ColorBox(source){
        return (
            <TouchableOpacity onPress={() => this.onShowColorModal(source)}>
                <View style={[this.styles.colorBoxSmall, {backgroundColor:
                    source.color == 1 ? AppStyles.chartLine1Stroke : 
                    source.color == 2 ? AppStyles.chartLine2Stroke : 
                    source.color == 3 ? AppStyles.chartLine3Stroke : 
                    source.color == 4 ? AppStyles.chartLine4Stroke : 
                    source.color == 5 ? AppStyles.chartLine5Stroke : 
                    source.color == 6 ? AppStyles.chartLine6Stroke : 
                    source.color == 7 ? AppStyles.chartLine7Stroke : 
                    source.color == 8 ? AppStyles.chartLine8Stroke :
                    AppStyles.chartLine1Stroke
                }]}></View>
            </TouchableOpacity>
        );
    }

    // Change Data Source Input ////////////////////////////////////////////////////////////////////////////

    onChangeSourceInput(source, inputId){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        chart.sources[i].inputId = inputId;
        chart.sources[i].input = source.task.inputs.filter(a => a.id == inputId)[0];
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Change Data Source Label ////////////////////////////////////////////////////////////////////////////

    onChangeSourceLabel(source, text){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        chart.sources[i].label = text;
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Change Data Source Date Offset /////////////////////////////////////////////////////////////////////

    onChangeSourceOffset(source, value){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        chart.sources[i].offset = value == null ? null : parseFloat(value);
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Change Data Source Color ////////////////////////////////////////////////////////////////////////////

    onShowColorModal(source){
        global.Modal.setContent('Select Color for Data Source', (
            <View style={[this.styles.modalMenuContainer, this.styles.colorBoxes]}>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 1)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine1Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 2)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine2Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 3)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine3Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 4)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine4Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 5)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine5Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 6)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine6Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 7)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine7Stroke}]}></View>
                    </TouchableOpacity>
                </View>
                <View style={this.styles.colorBoxContainer}>
                    <TouchableOpacity onPress={() => this.onChangeSourceColor(source, 8)}>
                        <View style={[this.styles.colorBox, {backgroundColor:AppStyles.chartLine8Stroke}]}></View>
                    </TouchableOpacity>
                </View>
            </View>
        ));
        global.Modal.show();
    }

    onChangeSourceColor(source, color){
        global.Modal.hide();
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        chart.sources[i].color = color;
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Check List Minimum Condition Type ///////////////////////////////////////////////////////////////////
    onChangeConditionType(source, value){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        chart.sources[i].style = value;
        if(value == 3 && chart.sources[i].inputId == null && chart.sources[i].task.inputs){
            const types = chart.sources[i].task.inputs.map(a => a.type);
            for(let x = 0; x < types.length; x++){
                if([0, 5, 6, 7].indexOf(types[x]) >= 0){
                    chart.sources[i].inputId = chart.sources[i].task.inputs[x].id;
                    chart.sources[i].input = chart.sources[i].task.inputs[x];
                    break;
                }
            }
            
        }
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Filters ///////////////////////////////////////////////////////////////////////////////////////////////\

    getOperatorTypes(type){
        switch(type){
            case 0: case 2: case 3: case 4: case 5: case 7: //number, date, time, date & time, currency, 5 star
                return [
                    {label:'>=', detail:'>= (greater or equal to)', value:1},
                    {label:'<=', detail:'<= (less than or equal to)', value:2},
                    {label:'==', detail:'== (equal to)', value:3},
                ];
            case 6: case 10: //yes/no, list
                return [
                    {label:'==', detail:'== (equal to)', value:3},
                ];
            case 1: case 8: case 9: //text, location, URL link
                return [
                    {label:'==', detail:'== (equal to)', value:3},
                    {label:'has', detail:'has (contains)', value:4}
                ];
        }
    }

    onPressAddFilter(source){
        global.Modal.setContent('Select Input For Filter', (
            <View style={this.styles.modalMenuContainer}>
                {source.task.inputs.map((input) => {
                    return (
                        <TouchableOpacity key={input.id} onPress={() => {this.selectFilterInput(source, input);}}>
                        <View style={this.styles.modalItemContainer}>
                            <Text style={this.styles.modalItemText}>{input.name}</Text>
                        </View>
                        </TouchableOpacity>
                    );
                })}
            </View>
        ));
        global.Modal.show();
    }

    selectFilterInput(source, input){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        let filters = source.filters || [];
        filters.push(JSON.stringify({
            inputId:input.id, 
            inputType: input.type,
            type:this.getOperatorTypes(input.type)[0].value, //default operator type
            value:''
        }));
        chart.sources[i].filters = filters;
        this.setState({chart:chart}, () => {
            global.Modal.hide();
            this.renderSources();
            this.validateForm();
        });
    }

    onChangeFilterInput(source, index, value){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        let filter = JSON.parse(chart.sources[i].filters[index]);
        const input = source.task.inputs[source.task.inputs.map(a => a.id).indexOf(value)];
        filter.inputId = input.id;
        //since we're changing the filter input, we must reset filter type & value
        filter.inputType = input.type,
        filter.type = this.getOperatorTypes(input.type)[0].value
        filter.value = '';
        chart.sources[i].filters[index] = JSON.stringify(filter);
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onChangeFilterOperator(source, index, value){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        let filter = JSON.parse(source.filters[index]);
        filter.type = value;
        chart.sources[i].filters[index] = JSON.stringify(filter);
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onChangeFilterValue(source, index, value){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        let filter = JSON.parse(chart.sources[i].filters[index]);
        filter.value = value;
        chart.sources[i].filters[index] = JSON.stringify(filter);
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    onChangeFilterListValue(source, index, item){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        let filter = JSON.parse(chart.sources[i].filters[index]);
        let lists = this.state.lists || {};
        filter.value = item.id;
        lists[item.id] = item.label;
        chart.sources[i].filters[index] = JSON.stringify(filter);
        this.setState({chart:chart, lists:lists}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    removeFilter(source, index){
        let chart = this.state.chart;
        const i = chart.sources.indexOf(source);
        chart.sources[i].filters.splice(index, 1);
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Remove Data Source ////////////////////////////////////////////////////////////////////////////////////////
    
    removeSource(source){
        let chart = this.state.chart;
        chart.sources = chart.sources.filter(a => a != source);
        this.setState({chart:chart}, () => {
            this.renderSources();
            this.validateForm();
        });
    }

    // Render Chart /////////////////////////////////////////////////////////////////////////////////////////
    renderChart(){
        let {width} = Dimensions.get('window');
        let chart = this.state.chart;
        let chartItem = [];
        switch(chart.type){
            case 1: //line chart
                chartItem = (
                    <LineChart
                    chart={chart}
                    days={this.state.days}
                    dateStart={this.state.datestart}
                    width={width}
                    height={120}
                    update={this.state.update+1}
                    navigation={this.props.navigation}
                    />
                ); 
                break;
            case 2: //time range
                chartItem = (
                    <TimeRange
                    chart={chart}
                    days={this.state.days}
                    dateStart={this.state.datestart}
                    width={width}
                    update={this.state.update+1}
                    navigation={this.props.navigation}
                    />
                ); 
                break;
            case 5: case 6: case 7: case 8:
                chartItem = (
                    <Statistic
                    chart={chart}
                    days={this.state.days}
                    dateStart={this.state.datestart}
                    width={width}
                    update={this.state.update+1}
                    navigation={this.props.navigation}
                    />
                ); 
                break;
            case 9:
                chartItem = (
                    <CheckList
                    chart={chart}
                    days={this.state.days}
                    dateStart={this.state.datestart}
                    width={width}
                    update={this.state.update+1}
                    navigation={this.props.navigation}
                    />
                ); 
                break;
        }
        this.setState({update:this.state.update+1, chartItem:chartItem});
    }

    // Validate Form ////////////////////////////////////////////////////////////////////////////////////////
    validateForm(){
        const chart = this.state.chart;
        let valid = true;
        let sourceType = 1;
        switch(chart.type){
            case 2: case 3: case 9:
                sourceType = 2;
                break;
        }
        for(let x = 0; x < chart.sources.length; x++){
            const source = chart.sources[x];
            if(sourceType == 1){
                //check for required input
                if(source.inputId == null){
                    valid = false;
                    break;
                }
            }

            if(chart.type == 9){
                //check list
                if(source.offset == null || source.offset <= 0){
                    valid = false;
                    break;
                }
            }

            //check filters
            if(source.filters != null && source.filters.length > 0){
                for(let y = 0; y < source.filters.length; y++){
                    const filter = JSON.parse(source.filters[y]);
                    if(filter.inputId == null || filter.inputId < 0){
                        valid = false;
                    }
                    if(filter.inputType == null || filter.inputType < 0){
                        valid = false;
                    }
                    if(filter.value == null || filter.value == ''){
                        valid = false;
                    }
                }
            }
        }

        this.setState({edited:valid});
    }

    // Save Chart ///////////////////////////////////////////////////////////////////////////////////////////

    onPressButtonSave(){
        const dbCharts = new DbCharts();
        dbCharts.CreateChart(this.state.chart);
        
        //update all charts within chart managers
        this.updateEmitter.emit('update-charts', null, null, null, true);

        //navigate back
        global.navigate(this, 'Analytics');
    }

    render() {
        let sources = [];
        if(this.state.chart.sources.length > 0){
            sources = this.state.sourcesList;
        }else{
            sources = (
                <View style={this.styles.containerDescription}>
                    <ToolTip background={AppStyles.altBackgroundColor} text="Add data sources from one or more tasks to generate your chart with"/>
                </View>
            );
        }
        let chartType = this.chartType[this.chartType.map(a => a.value).indexOf(this.state.chart.type)];
        return (
            <Form {...this.props} title={this.state.title} screen="Chart" bodyTitle="Data Sources" onLayout={this.onLayout}
            edited={this.state.edited} onPressAddInput={this.state.chart.sources.length >= 8 ? null : this.onPressAddInput} 
            onPressSave={this.onPressButtonSave} backButton={this.hardwareBackPress}>
                <FormHeader>
                    <View style={this.styles.chartContainer}>
                        {this.state.chartItem}
                    </View>
                    <View style={this.styles.headerContainer}>
                        <View style={this.styles.input}>
                            <Text style={this.styles.fieldTitle}>Chart Name</Text>
                            <Textbox
                                value={this.state.chart.name}
                                style={this.styles.inputField} 
                                placeholder="My Chart"
                                returnKeyType={'done'}
                                blurOnSubmit={false}
                                onChangeText={this.onChartNameChange}
                                maxLength={24}
                            />
                        </View>
                        <View style={this.styles.input}>
                            <Text style={this.styles.fieldTitle}>Chart Type</Text>
                            <Picker
                                style={this.styles.pickerStyle}
                                itemStyle={this.styles.pickerItemStyle}
                                selectedValue={this.state.chart.type}
                                onValueChange={this.onChartTypeChange}
                                items={this.chartType.filter(a => a.show == true)}
                                title="Select A Chart Type"
                            />
                        </View>
                        {this.state.chart.hasOffset == true && 
                            <View style={this.styles.input}>
                                <Text style={this.styles.fieldTitle}>Date Offset</Text>
                                <Picker
                                    style={this.styles.pickerStyle}
                                    itemStyle={this.styles.pickerItemStyle}
                                    selectedValue={this.state.chart.offset}
                                    onValueChange={this.onChartDateOffsetChange}
                                    items={[
                                        {label:'None', value:0},
                                        {label:'Day', value:1},
                                        {label:'Week', value:2},
                                        {label:'Month', value:3},
                                        {label:'Year', value:4}
                                    ]}
                                    title="Select A Date Offset"
                                />
                            </View>
                        }
                        
                        {this.state.chart.type == 9 && 
                            <View style={this.styles.input}>
                                <Text style={this.styles.fieldTitle}>Check List - Date Range</Text>
                                <Picker
                                    style={this.styles.pickerStyle}
                                    itemStyle={this.styles.pickerItemStyle}
                                    selectedValue={this.state.chart.offset}
                                    onValueChange={this.onChartDateOffsetChange}
                                    items={[
                                        {label:'Today', value:1},
                                        {label:'This Week', value:2},
                                        {label:'This Month', value:3},
                                        {label:'This Quarter', value:4},
                                        {label:'This Year', value:5}
                                    ]}
                                    title="Select Date Range"
                                />
                            </View>
                        }

                        {chartType.styles != null && 
                            <View style={this.styles.input}>
                            <Text style={this.styles.fieldTitle}>Chart Style</Text>
                            <Picker
                                style={this.styles.pickerStyle}
                                itemStyle={this.styles.pickerItemStyle}
                                selectedValue={this.state.chart.style || 1}
                                onValueChange={this.onChartStyleChange}
                                items={chartType.styles}
                                title="Select A Chart Style"
                            />
                            </View>
                        }
                        {chartType.value >= 5 && chartType.value <= 8 && 
                            <View style={this.styles.input}>
                                <CheckBox text="Outline Around Statistic" defaultValue={this.state.chart.outline} onChange={this.onStatisticOutlineChange}/>
                            </View>
                        }
                        <View style={this.styles.input}>
                            <CheckBox text="Featured on the Overview Screen" defaultValue={this.state.chart.featured} onChange={this.onFeaturedChange}/>
                        </View>
                        <View style={this.styles.input}>
                            <CheckBox text="Enable Advanced Filters" defaultValue={this.state.chart.filters} onChange={this.onFiltersChange}/>
                        </View>

                    </View>
                </FormHeader>
                <FormBody>
                    <View style={this.styles.sourcesContainer}>
                        {sources}
                    </View>
                </FormBody>
            </Form>
        );
    }

    styles = StyleSheet.create({
        body:{position:'absolute', top:0, bottom:0, left:0, right:0, backgroundColor:AppStyles.altBackgroundColor},
        headerContainer:{paddingHorizontal:AppStyles.paddingLarge, paddingBottom:AppStyles.paddingLarge},
        chartContainer:{minHeight:80 * AppStyles.vw, paddingTop:AppStyles.paddingLarge},

        //Chart Information
        noChart:{fontSize:AppStyles.titleFontSize, paddingTop:AppStyles.paddingLarge, opacity:0.3, alignSelf:'center'},
        input:{paddingBottom:AppStyles.paddingLarge},
        fieldTitle: {fontSize:AppStyles.fieldFontSize, fontWeight:'bold'},
        inputField:{fontSize:AppStyles.titleFontSize},
        pickerStyle:{},
        pickerItemStyle:{fontSize:AppStyles.titleFontSize},
        containerDescription: {paddingTop:AppStyles.paddingLarge, paddingHorizontal:AppStyles.paddingLarger, paddingBottom:AppStyles.paddingFooterSpace, flexDirection:'column',  alignItems:'center'},
        padRight:{paddingRight:AppStyles.padding},
        row:{flexDirection:'row'},

        //Sources
        sourcesContainer:{paddingBottom:AppStyles.paddingFooterSpace},
        iconArrow:{position:'absolute', left:0, paddingTop:AppStyles.paddingMedium},
        sourceContainer:{paddingHorizontal:AppStyles.paddingLarge, borderBottomColor:AppStyles.altSeparatorColor, borderBottomWidth:1},
        sourceHeader:{flex:1, flexDirection:'row', justifyContent:'space-between'},
        sourceBody:{flexDirection:'row', justifyContent:'space-between'},
        sourceField:{flexDirection:'column'},
        sourceInput:{marginBottom:AppStyles.paddingSmall},
        fieldLabel:{fontSize:AppStyles.fieldFontSize, fontWeight:'bold', marginTop:AppStyles.paddingSmall, marginRight:AppStyles.paddingXSmall},
        fieldLabelTextbox:{marginBottom:AppStyles.paddingSmall},
        sourceNumericField:{flexDirection:'row', marginTop:-5, marginBottom:AppStyles.paddingSmall},
        fieldNumericInput:{width:80 * AppStyles.vw, marginRight:AppStyles.paddingSmall, marginBottom:AppStyles.paddingSmaller},
        fieldNumericLabel:{marginTop:AppStyles.padding + AppStyles.paddingXSmall, marginRight:AppStyles.paddingSmall},
        sourceColumn:{flexDirection:'row'},
        sourceTitle:{fontSize:AppStyles.headerFontSize, paddingTop:AppStyles.paddingSmall},
        sourceClose:{position:'relative', top:AppStyles.padding, opacity:0.5},

        //modal window
        modalContainer:{backgroundColor:AppStyles.backgroundColor, minWidth:'50%', padding:AppStyles.paddingLarger},
        modalMenuContainer:{backgroundColor:AppStyles.backgroundColor, maxWidth:600 * AppStyles.vw},
        modalItemContainer:{paddingVertical:AppStyles.padding, paddingHorizontal:AppStyles.paddingLarger, borderBottomColor: AppStyles.separatorColor, borderBottomWidth:1},
        
        //Color Picker
        colorBoxes:{flex:1, flexDirection:'row', justifyContent:'space-between', flexWrap:'wrap', maxWidth:600 * AppStyles.vw, padding:10, borderRadius:5},
        colorBoxContainer:{padding:AppStyles.paddingSmall},
        colorBox:{width:AppStyles.icon, height:AppStyles.icon, borderRadius:5},
        colorBoxSmall:{width:AppStyles.iconSmaller, height:AppStyles.iconSmaller, borderRadius:5},

        //Filters
        filters:{},
        filtersHead:{flexDirection:'row', justifyContent:'space-between', paddingBottom:AppStyles.paddingSmall},
        buttonAddFilter:{marginTop:AppStyles.paddingSmall},
        filterContainer:{position:'relative', zIndex:1, flexDirection:'row', justifyContent:'space-between', marginTop:AppStyles.paddingSmall, marginBottom:AppStyles.padding, borderWidth:1, borderColor:AppStyles.color, borderRadius:5, padding:AppStyles.paddingXSmall, paddingBottom:AppStyles.paddingSmall, paddingHorizontal:AppStyles.paddingSmall},
        filterInputs:{flexDirection:'row'},
        filterField:{paddingRight:AppStyles.paddingSmaller},
        filterArrow:{position:'absolute', zIndex:10, width:'100%', justifyContent:'center', flexDirection:'row', top:(-31 + AppStyles.paddingSmall) * AppStyles.vw},
        filterClose:{position:'relative', top:AppStyles.padding, opacity:0.5},
        operatorPicker:{width:80}
    });
}