import React from 'react';
import './Configuration.css';
import {connect} from 'react-redux';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import ConfigurationItem from '../../components/ConfigurationItem/ConfigurationItem';
import Modal from '../../components/UI/Modal/Modal';
import IPCContainer from '../IPCContainer/IPCContainer';
import {displayConfiguration} from '../../redux/actions/mount_actions';
import {notifyError} from '../../redux/actions/error_actions';

const Constants = require('../../constants');

class Configuration extends IPCContainer {
  constructor(props) {
    super(props);

    this.setRequestHandler(Constants.IPC_Get_Config_Template_Reply, this.onGetConfigTemplateReply);
    this.setRequestHandler(Constants.IPC_Get_Config_Reply, this.onGetConfigReply);
    this.setRequestHandler(Constants.IPC_Set_Config_Values_Reply, this.onSetConfigValuesReply);
  }

  _isMounted = false;

  state = {
    ChangedItems: [],
    ChangedObjectLookup: null,
    ObjectLookup: {},
    OriginalItemList: [],
    OriginalObjectLookup: {},
    ItemList: [],
    Saving: false,
    ShowAdvanced: false,
    Template: {}
  };

  checkSaveRequired = () => {
    const changedItems = [];
    let i = 0;
    for (const item of this.state.ItemList) {
      if (this.state.OriginalItemList[i++].value !== item.value) {
        changedItems.push(item);
      }
    }

    let changedObjectLookup = null;
    for (const key of Object.keys(this.state.ObjectLookup)) {
      const changedObjectItems = [];
      let j = 0;
      for (const item of this.state.ObjectLookup[key]) {
        if (this.state.OriginalObjectLookup[key][j++].value !== item.value) {
          changedObjectItems.push(item);
        }
      }

      if (changedObjectItems.length > 0) {
        if (changedObjectLookup === null) {
          changedObjectLookup = {};
        }
        changedObjectLookup[key] = changedObjectItems;
      }
    }

    if ((changedItems.length > 0) || changedObjectLookup) {
      this.setState({
        ChangedItems: changedItems,
        ChangedObjectLookup: changedObjectLookup,
      });
    } else {
      this.props.hideConfiguration();
    }
  };

  componentDidMount() {
    this._isMounted = true;
    this.sendRequest(Constants.IPC_Get_Config_Template, {
      Provider: this.props.DisplayConfiguration,
      Version: this.props.version,
    });
  }

  componentWillUnmount() {
    this._isMounted = false;
    super.componentWillUnmount();
  }

  createItemList = (config, template) => {
    const objectList = [];
    const itemList = Object
      .keys(config)
      .map(key => {
        return {
          advanced: template[key] ? template[key].advanced : false,
          label: key,
          value: config[key],
        };
      })
      .filter(i=> {
        let ret = template[i.label];
        if (ret && (template[i.label].type === 'object')) {
          objectList.push(i);
          ret = false;
        }
        return ret;
      });

    return {
      ObjectList: objectList,
      ItemList: itemList,
    }
  };

  handleItemChanged = (target, idx) => {
    const itemList = [
      ...this.state.ItemList
    ];
    itemList[idx].value = target.value.toString();
    this.setState({
      ItemList: itemList
    });
  };

  handleObjectItemChanged = (target, name, idx) => {
    const itemList = [
      ...this.state.ObjectLookup[name]
    ];
    const objectLookup = {
      ...this.state.ObjectLookup,
    };

    itemList[idx].value = target.value.toString();
    objectLookup[name] = itemList;
    this.setState({
      ObjectLookup: objectLookup,
    });
  };

  onGetConfigReply = (event, arg) => {
    if (arg.data.Success) {
      const list = this.createItemList(arg.data.Config, this.state.Template);
      const itemListCopy = JSON.parse(JSON.stringify(list.ItemList));

      let objectLookup = {};
      for (const obj of list.ObjectList) {
        const list2 = this.createItemList(obj.value, this.state.Template[obj.label].template);
        objectLookup[obj.label] = list2.ItemList;
      }
      const objectLookupCopy = JSON.parse(JSON.stringify(objectLookup));

      this.setState({
        ItemList: list.ItemList,
        ObjectLookup: objectLookup,
        OriginalItemList: itemListCopy,
        OriginalObjectLookup: objectLookupCopy,
      });
    } else {
      this.props.notifyError(arg.data.Error);
    }
  };

  onGetConfigTemplateReply = (event, arg) => {
    if (arg.data.Success) {
      this.setState({
        Template: arg.data.Template,
      }, ()=> {
        this.sendRequest(Constants.IPC_Get_Config, {
          Provider: this.props.DisplayConfiguration,
          Version: this.props.version,
        });
      });
    } else {
      this.props.notifyError(arg.data.Error, false, () => {
        if (this._isMounted) {
          this.props.hideConfiguration();
        }
      });
    }
  };

  onSetConfigValuesReply = () => {
    this.props.hideConfiguration();
  };

  saveAndClose = () => {
    this.setState({
      Saving: true,
    }, ()=> {
      const changedItems = [];
      for (const item of this.state.ChangedItems) {
        changedItems.push({
          Name: item.label,
          Value: item.value,
        });
      }

      if (this.state.ChangedObjectLookup) {
        for (const key of Object.keys(this.state.ChangedObjectLookup)) {
          for (const item of this.state.ChangedObjectLookup[key]) {
            changedItems.push({
              Name: key + '.' + item.label,
              Value: item.value,
            });
          }
        }
      }

      this.sendRequest(Constants.IPC_Set_Config_Values, {
        Items: changedItems,
        Provider: this.props.DisplayConfiguration,
        Version: this.props.version,
      });
    });
  };

  render() {
    let confirmSave = null;
    if ((this.state.ChangedItems.length > 0) || this.state.ChangedObjectLookup) {
      confirmSave = (
        <Modal>
          <Box dxStyle={{width: '40vw', padding: '4px'}}>
            <h1 style={{width: '100%', textAlign: 'center'}}>Save Changes?</h1>
            <table width='100%'><tbody>
              <tr>
                <td align='center' width='50%'><Button clicked={this.saveAndClose} disabled={this.state.Saving}>Yes</Button></td>
                <td align='center' width='50%'><Button clicked={this.props.hideConfiguration} disabled={this.state.Saving}>No</Button></td>
              </tr>
            </tbody></table>
          </Box>
        </Modal>
      );
    }

    const configurationItems = this.state.ItemList
      .map((k, i) => {
        return (
          ((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
            <ConfigurationItem advanced={k.advanced}
                               changed={e=>this.handleItemChanged(e, i)}
                               items={this.state.Template[k.label].items}
                               key={i}
                               label={k.label}
                               template={this.state.Template[k.label]}
                               value={k.value}/> :
            null)
      });

    let objectItems = [];
    for (const key of Object.keys(this.state.ObjectLookup)) {
      objectItems.push((
        <div key={key}>
          <h1>{key}</h1>
          <div>
            {
              this.state.ObjectLookup[key].map((k, i) => {
                return (
                  ((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
                    <ConfigurationItem advanced={k.advanced}
                                       changed={e=>this.handleObjectItemChanged(e, key, i)}
                                       items={this.state.Template[key].template[k.label].items}
                                       key={i}
                                       label={k.label}
                                       template={this.state.Template[key].template[k.label]}
                                       value={k.value}/> :
                    null)
              })
            }
          </div>
        </div>
      ));
    }

    return (
      <div className={'Configuration'}>
        {confirmSave}
        <Box dxDark dxStyle={{padding: '8px'}}>
          <div style={{float: 'right', margin: 0, padding: 0, marginTop: '-4px', boxSizing: 'border-box', display: 'block'}}>
            <b style={{cursor: 'pointer'}}
               onClick={this.checkSaveRequired}>X</b>
          </div>
          <h1 style={{width: '100%', textAlign: 'center'}}>{this.props.DisplayConfiguration + ' Configuration'}</h1>
          <div style={{overflowY: 'auto', height: '90%'}}>
            {objectItems}
            {(configurationItems.length > 0) ? <h1>Settings</h1> : null}
            {configurationItems}
          </div>
        </Box>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    DisplayConfiguration: state.mounts.DisplayConfiguration,
  }
};

const mapDispatchToProps = dispatch => {
  return {
    notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
    hideConfiguration: () => dispatch(displayConfiguration(null)),
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(Configuration);