import React from 'react';
import Box from '../../components/UI/Box/Box';
import Button from '../../components/UI/Button/Button';
import {connect} from 'react-redux';
import './MountItems.css';
import Modal from '../../components/UI/Modal/Modal';
import MountItem from '../../components/MountItem/MountItem';
import IPCContainer from '../IPCContainer/IPCContainer';
import {displayConfiguration, setAutoMountProcessed, setBusy} from '../../redux/actions/mount_actions';

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

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

    for (const provider of Constants.PROVIDER_LIST) {
      this.state[provider] = {
        AllowMount: false,
        DriveLetters: [],
        Mounted: false,
      };
    }

    this.setRequestHandler(Constants.IPC_Detect_Mounts_Reply, this.onDetectMountsReply);
    this.setRequestHandler(Constants.IPC_Mount_Drive_Reply, this.onMountDriveReply);
    this.setRequestHandler(Constants.IPC_Unmount_Drive_Reply, this.onUnmountDriveReply);

    this.detectMounts();
  }

  retryIntervals = {};

  state = {
    DisplayRetry: false,
    RetryItems: {},
  };

  cancelRetryMount = (storageType, stateCallback) => {
    clearInterval(this.retryIntervals[storageType]);
    delete this.retryIntervals[storageType];

    if (stateCallback) {
      let retryItems = {
        ...this.state.RetryItems,
      };
      delete retryItems[storageType];
      this.setState({
        DisplayRetry: Object.keys(retryItems).length > 0,
        RetryItems: retryItems,
      }, () => {
        if (this.state.DisplayRetry) {
          this.sendRequest(Constants.IPC_Show_Window);
        }
        stateCallback();
      });
    }
  };

  componentWillUnmount() {
    for (const storageType in this.state.RetryItems) {
      if (this.state.RetryItems.hasOwnProperty(storageType)) {
        this.cancelRetryMount(storageType);
      }
    }

    super.componentWillUnmount();
  };

  detectMounts = ()=> {
    if (!this.state.DisplayRetry) {
      this.props.setMountsBusy(true);
      this.sendRequest(Constants.IPC_Detect_Mounts, {
        Version: this.props.version,
      });
    }
  };

  handleBrowseLocation = (storageType, location) => {
    location = this.sendSyncRequest(Constants.IPC_Browse_Directory, {
      Title: storageType + ' Mount Location',
      Location: location,
    });
    if (location && (location.length > 0)) {
      this.handleMountLocationChanged(storageType, location);
    }
  };

  handleMountLocationChanged = (storageType, value) => {
    if (this.props.Platform === 'win32') {
      this.props.changed(storageType, this.state[storageType].DriveLetters[value]);
    } else {
      this.props.changed(storageType, value);
    }
  };

  handleMountUnMount = (storageType, mount, location) => {
    if (!location || (location.trim().length === 0)) {
      this.props.errorHandler('Mount location is not set');
    } else {
      let allowAction = true;
      if (mount) {
        let result = this.sendSyncRequest(Constants.IPC_Check_Daemon_Version, {
          StorageType: storageType,
          Version: this.props.version
        }).data;
        if (result.Success) {
          if (result.Valid) {
            if (this.props.Platform !== 'win32') {
              result = this.sendSyncRequest(Constants.IPC_Check_Mount_Location, {
                Location: location,
              });
              if (!result.Success) {
                allowAction = false;
                this.props.errorHandler(result.Error.toString());
              }
            }
          } else {
            allowAction = false;
            this.props.errorHandler("Incompatible " + storageType + " daemon. Please upgrade " + storageType);
          }
        } else {
          allowAction = false;
          this.props.errorHandler(result.Error.toString());
        }
      }

      if (allowAction) {
        const storageState = {
          ...this.state[storageType],
          AllowMount: false,
        };

        this.props.setMountsBusy(true);

        this.setState({
          [storageType]: storageState,
        }, () => {
          if (mount) {
            this.sendRequest(Constants.IPC_Mount_Drive, {
              Location: location,
              NoConsoleSupported: this.props.noConsoleSupported,
              StorageType: storageType,
              Version: this.props.version,
            });
          } else {
            this.sendRequest(Constants.IPC_Unmount_Drive, {
              Location: location,
              StorageType: storageType,
              Version: this.props.version,
            });
          }
        });
      }
    }
  };

  onDetectMountsReply = (event, arg) => {
    if (!this.state.DisplayRetry && arg.data.Success) {
      let state = {};
      let mountsBusy = false;
      for (const provider of Constants.PROVIDER_LIST) {
        state[provider] = {
          ...this.state[provider],
          AllowMount: true,
          DriveLetters: (arg.data.DriveLetters[provider]),
          Mounted: (arg.data.Locations[provider].length > 0),
        };
        mountsBusy = mountsBusy || state[provider].Mounted;
      }
      this.props.setMountsBusy(mountsBusy);

      this.setState(state, () => {
        const updateMountLocation = (data, provider) => {
          const providerLower = provider.toLowerCase();
          let location = data.Locations[provider];
          if (location.length === 0) {
            location = (this.props.Platform === 'win32') ?
              this.props[providerLower].MountLocation || data.DriveLetters[provider][0] :
              this.props[providerLower].MountLocation;
          }
          if (location !== this.props[providerLower].MountLocation) {
            this.props.changed(provider, location);
          }
        };
        
        for (const provider of Constants.PROVIDER_LIST) {
          updateMountLocation(arg.data, provider);
        }

        this.performAutoMount();
      });
    } else {
      this.props.errorHandler(arg.data.Error);
    }
  };

  onMountDriveReply = (event, arg) => {
    const state = {
      ...this.state[arg.data.StorageType],
      Mounted: arg.data.Success,
    };
    this.setState({
      [arg.data.StorageType]: state,
    }, ()=> {
      this.detectMounts();
    });
  };

  onUnmountDriveReply = (event, arg) => {
    if (arg && arg.data && !arg.data.Expected && arg.data.Location && this.props[arg.data.StorageType.toLowerCase()].AutoRestart) {
      const storageType = arg.data.StorageType;
      if (!this.state.RetryItems[storageType]) {
        let retryItems = {
          ...this.state.RetryItems
        };
        retryItems[storageType] = {
          RetrySeconds: 10,
        };
        const storageState = {
          ...this.state[arg.data.StorageType],
          AllowMount: false,
          Mounted: false,
        };
        this.setState({
          [storageType]: storageState,
          DisplayRetry: true,
          RetryItems: retryItems,
        }, () => {
          this.sendRequest(Constants.IPC_Show_Window);
          this.retryIntervals[storageType] = setInterval(() => {
            let retryItems = {
              ...this.state.RetryItems,
            };
            const retrySeconds = retryItems[storageType].RetrySeconds - 1;
            if (retrySeconds === 0) {
              this.cancelRetryMount(storageType, () => {
                this.handleMountUnMount(storageType, true, arg.data.Location);
              });
            } else {
              retryItems[storageType].RetrySeconds = retrySeconds;
              this.setState({
                RetryItems: retryItems,
              });
            }
          },1000);
        });
      }
    } else {
      this.detectMounts();
    }
  };

  performAutoMount = ()=> {
    if (!this.props.AutoMountProcessed) {
      this.props.setAutoMountProcessed(true);

      const processAutoMount = (provider) => {
        const providerLower = provider.toLowerCase();
        if (this.props[providerLower].AutoMount &&
          !this.state[provider].Mounted &&
          (this.props[providerLower].MountLocation.length > 0)) {
          this.handleMountUnMount(provider, true, this.props[providerLower].MountLocation);
        }
      };

      for (const provider of Constants.PROVIDER_LIST) {
        processAutoMount(provider);
      }
    }
  };

  render() {
    let retryDisplay;
    if (this.state.DisplayRetry) {
      let retryList = [];
      let retryListCount = 0;
      for (const storageType in this.state.RetryItems) {
        if (this.state.RetryItems.hasOwnProperty(storageType)) {
          retryListCount++;
          retryList.push(<Button
            clicked={()=>this.cancelRetryMount(storageType, ()=> this.detectMounts())}
            key={'b' + retryListCount}>Cancel {storageType} Remount ({this.state.RetryItems[storageType].RetrySeconds}s)</Button>);
          if (retryListCount < Object.keys(this.state.RetryItems).length) {
            retryList.push(<div style={{paddingTop: '8px'}} key={'d' + retryListCount}/>);
          }
        }
      }

      retryDisplay = (
        <Modal>
          <Box dxStyle={{padding: '8px', minWidth: '70vw'}}>
            <h1 style={{textAlign: 'center', paddingBottom: '8px', color: 'var(--text_color_error)'}}>Mount Failed</h1>
            {retryList}
          </Box>
        </Modal>
      )
    }

    let items = [];
    for (const provider of Constants.PROVIDER_LIST) {
      const providerLower = provider.toLowerCase();
      items.push((
        <MountItem allowConfig={this.props.allowConfig}
                   allowMount={this.state[provider].AllowMount}
                   autoMount={this.props[providerLower].AutoMount}
                   autoMountChanged={(e)=>this.props.autoMountChanged(provider, e)}
                   autoRestart={this.props[providerLower].AutoRestart}
                   autoRestartChanged={(e)=>this.props.autoRestartChanged(provider, e)}
                   browseClicked={this.handleBrowseLocation}
                   changed={(e) => this.handleMountLocationChanged(provider, e.target.value)}
                   clicked={this.handleMountUnMount}
                   configClicked={()=>this.props.displayConfiguration(provider)}
                   items={this.state[provider].DriveLetters}
                   key={'mi_' + items.length}
                   location={this.props[providerLower].MountLocation}
                   mounted={this.state[provider].Mounted}
                   title={provider} />
      ));
      if (items.length !== this.state.length) {
        items.push(<div key={'di_' + items.length}
                        style={{paddingTop: '12px'}} />)
      }
    }
    
    return (
      <div className={'MountItems'}>
        {retryDisplay}
        {items}
      </div>);
  }
}

const mapStateToProps = state => {
  return {
    AutoMountProcessed: state.mounts.AutoMountProcessed,
    Platform: state.common.Platform,
  }
};

const mapDispatchToProps = dispatch => {
  return {
    displayConfiguration: storageType => dispatch(displayConfiguration(storageType)),
    setAutoMountProcessed: processed => dispatch(setAutoMountProcessed(processed)),
    setMountsBusy: busy => dispatch(setBusy(busy)),
  }
};

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