import React from 'react';
import {withNamespaces} from 'react-i18next';

import {ApiRequest, GET, POST} from "../../lib/ApiRequest";
import {injectSheet, withTheme} from '../../lib/theme';
import ControlBar from "./ControlBar";
import ContentPane from "./ContentPane";
import {withPusher} from "../PushToApi/Pusher";

const theming = () => ({
    wrapper: {},
});

class Explorer extends React.Component {

    state = {
        list: false,
        currentDir: '',
        viewMode: 'list',
        loaded: false
    };

    toggleViewMode = () => {
        let next = 'list';
        if('list' === this.state.viewMode) {
            next = 'grid';
        }
        window.localStorage.setItem('explorer-viewMode', next);
        this.setState({
            viewMode: next
        })
    };

    componentDidMount() {
        let last_view_mode = window.localStorage.getItem('explorer-viewMode');
        if(null !== last_view_mode && '' !== last_view_mode.trim()) {
            this.setState({
                viewMode: last_view_mode
            })
        }
        this.loadList();
    }

    loadList = (folder) => {
        this.setState({loaded: 'progress'});
        (new ApiRequest('file', GET, 'files/list' + (folder ? '/' + encodeURIComponent(folder) : '')))
            .debug(true)
            .header({})
            .exec()
            .then((res) => {
                if(res && res.data) {

                    if(res.data.dir) {
                        res.data.dir = res.data.dir.map((elem, i) => {
                            elem.delete = () => {
                                this.deleteDir(elem.name, i);
                            };

                            elem.deleting = false;

                            elem.rename = (to) => {
                                this.renameDir(elem.name, to, i);
                            };

                            elem.renaming = false;

                            return elem;
                        });
                    }
                    if(res.data.file) {
                        res.data.file = res.data.file.map((elem, i) => {
                            elem.delete = () => {
                                this.deleteFile(elem.name, i);
                            };

                            elem.deleting = false;

                            elem.rename = (to) => {
                                this.renameFile(elem.name, to, i);
                            };

                            elem.renaming = false;

                            return elem;
                        });
                    }

                    this.setState({
                        list: res.data,
                        loaded: true
                    });
                } else {
                    this.setState({
                        loaded: 'error'
                    });
                }
            })
            .catch(() => {
                this.setState({
                    loaded: 'error'
                });
            });
    };

    loadParent = () => {
        const parentFolder = this.state.currentDir.split('/').splice(0, 1).join('/');

        this.setState({
            currentDir: parentFolder
        });

        this.loadList(parentFolder);

        if(this.props.onSwitchDir) {
            this.props.onSwitchDir(parentFolder);
        }

        if(this.props.clearSelect) {
            this.props.clearSelect();
        }
    };

    updateFileState = (index, evt) => {
        const list = {...this.state.list};
        const files = [...list.file];
        let file = {...files[index]};

        file = evt(file);

        file.delete = () => {
            this.deleteFile(file.name, index);
        };

        file.rename = (to) => {
            this.renameFile(file.name, to, index);
        };

        files[index] = file;
        list.file = files;

        this.setState({
            list
        });
    };

    deleteFile = (file, index) => {
        this.props.addPushing(
            {
                name: 'deleteFile',
                context: 'deleteFile',
                push: (resolve, reject) => {
                    this.updateFileState(index, (file) => {
                        file.deleting = 'progress';
                        return file;
                    });

                    (new ApiRequest('file', POST, 'files/delete-file/' + (this.state.currentDir ? encodeURIComponent(this.state.currentDir + '/' + file) : encodeURIComponent('/' + file))))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .then((data) => {
                if(data.error) {
                    this.updateFileState(index, (file) => {
                        file.deleting = 'error';
                        return file;
                    });
                    return;
                }

                this.updateFileState(index, (file) => {
                    file.deleting = 'success';
                    return file;
                });

                setTimeout(() => {
                    this.updateFileState(index, (file) => {
                        file.deleting = 'finished';
                        return file;
                    });
                }, 800);
            })
            .catch((data) => {
                if(data && !data.cancelled) {
                    this.updateFileState(index, (file) => {
                        file.deleting = 'error';
                        return file;
                    });
                }
            });
    };

    renameFile = (from, to, index) => {
        if(from === to) {
            return;
        }
        const newName = this.state.currentDir ? this.state.currentDir + '/' + to : '/' + to;
        this.props.addPushing(
            {
                name: 'renameFile',
                context: 'renameFile',
                push: (resolve, reject) => {
                    this.updateFileState(index, (file) => {
                        file.renaming = 'progress';
                        return file;
                    });

                    (new ApiRequest('file', POST,
                        'files/rename-file/' + (this.state.currentDir ? encodeURIComponent(this.state.currentDir + '/' + from) : encodeURIComponent('/' + from)),
                        {to: newName}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .then((data) => {
                if(data.error) {
                    this.updateFileState(index, (file) => {
                        file.renaming = 'error';
                        return file;
                    });
                    return;
                }

                this.updateFileState(index, (file) => {
                    file.renaming = 'success';
                    file.name = to;
                    return file;
                });

                setTimeout(() => {
                    this.updateFileState(index, (file) => {
                        file.renaming = false;
                        return file;
                    });
                }, 800);
            })
            .catch((data) => {
                if(data && !data.cancelled) {
                    this.updateFileState(index, (file) => {
                        file.renaming = 'error';
                        return file;
                    });
                }
            });
    };

    updateDirState = (index, evt) => {
        const list = {...this.state.list};
        const dirs = [...list.dir];
        let dir = {...dirs[index]};

        dir = evt(dir);

        dir.delete = () => {
            this.deleteDir(dir.name, index);
        };

        dir.rename = (to) => {
            this.renameDir(dir.name, to, index);
        };

        dirs[index] = dir;
        list.dir = dirs;

        this.setState({
            list
        });
    };

    deleteDir = (dir, index) => {
        this.props.addPushing(
            {
                name: 'deleteDir',
                context: 'deleteDir',
                push: (resolve, reject) => {
                    this.updateDirState(index, (dir) => {
                        dir.deleting = 'progress';
                        return dir;
                    });

                    (new ApiRequest('file', POST, 'files/delete-dir/' + (this.state.currentDir ? encodeURIComponent(this.state.currentDir + '/' + dir) : encodeURIComponent('/' + dir))))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .then((data) => {
                if(data.error) {
                    this.updateDirState(index, (dir) => {
                        dir.deleting = 'error';
                        return dir;
                    });
                    return;
                }

                this.updateDirState(index, (dir) => {
                    dir.deleting = 'success';
                    return dir;
                });

                setTimeout(() => {
                    this.updateDirState(index, (dir) => {
                        dir.deleting = 'finished';
                        return dir;
                    });
                }, 800);
            })
            .catch((data) => {
                if(data && !data.cancelled) {
                    this.updateDirState(index, (dir) => {
                        dir.deleting = 'error';
                        return dir;
                    });
                }
            });
    };

    renameDir = (from, to, index) => {
        if(from === to) {
            return;
        }
        const newName = this.state.currentDir ? this.state.currentDir + '/' + to : '/' + to;
        this.props.addPushing(
            {
                name: 'renameDir',
                context: 'renameDir',
                push: (resolve, reject) => {
                    this.updateDirState(index, (dir) => {
                        dir.renaming = 'progress';
                        return dir;
                    });

                    (new ApiRequest('file', POST,
                        'files/rename-dir/' + (this.state.currentDir ? encodeURIComponent(this.state.currentDir + '/' + from) : encodeURIComponent('/' + from)),
                        {to: newName}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .then((data) => {
                if(data.error) {
                    this.updateDirState(index, (dir) => {
                        dir.renaming = 'error';
                        return dir;
                    });
                    return;
                }

                this.updateDirState(index, (dir) => {
                    dir.renaming = 'success';
                    dir.name = to;
                    return dir;
                });

                setTimeout(() => {
                    this.updateDirState(index, (dir) => {
                        dir.renaming = false;
                        return dir;
                    });
                }, 800);
            })
            .catch((data) => {
                if(data && !data.cancelled) {
                    this.updateDirState(index, (dir) => {
                        dir.renaming = 'error';
                        return dir;
                    });
                }
            });
    };

    gotoSubDir = (dir) => {
        const nextDir = this.state.currentDir + '/' + dir;
        this.setState({
            currentDir: nextDir
        });

        this.loadList(nextDir);

        if(this.props.onSwitchDir) {
            this.props.onSwitchDir(nextDir);
        }

        if(this.props.clearSelect) {
            this.props.clearSelect();
        }
    };

    select = (type, itemId, shouldAdd) => {
        const {onSelect} = this.props;
        if(onSelect) {
            let fullId = '/' + itemId;
            if(this.state.currentDir) {
                fullId = this.state.currentDir + fullId;
            }
            onSelect(type, fullId, shouldAdd);
        }
    };

    render() {
        const {
            classes,
            selectFile, selectDir,
            multiple,
            hasSelected, selected
        } = this.props;
        const {viewMode} = this.state;

        return (
            <div className={classes.wrapper}>
                <ControlBar loadList={this.loadList}
                            viewMode={viewMode}
                            toggleViewMode={this.toggleViewMode}
                            loadParent={this.loadParent}
                            hasSelected={hasSelected}
                            currentDir={this.state.currentDir}/>

                <ContentPane gotoSubDir={this.gotoSubDir}
                             deleteDir={this.deleteDir}
                             renameDir={this.renameDir}
                             deleteFile={this.deleteFile}
                             renameFile={this.renameFile}
                             selectFile={selectFile}
                             selectDir={selectDir}
                             multiple={multiple}
                             onSelect={this.select}
                             currentDir={this.state.currentDir}
                             loaded={this.state.loaded}
                             list={this.state.list}
                             hasSelected={hasSelected}
                             selected={selected}
                             viewMode={viewMode}/>
            </div>
        );
    }
}

export default withNamespaces('file-explorer')(withPusher(withTheme(injectSheet(theming)(Explorer))));