import React from "react";
import { StickyContainer, Sticky } from "react-sticky";
import { Modal, NgIf, Icon, Dropdown, DropdownButton, DropdownList, DropdownItem, Input } from "../../components/";
import { extractEvents, extractTodos } from "../../helpers/org";
import { leftPad } from "../../helpers/common";
import { debounce, randomString } from "../../helpers/";
import { t } from "../../locales/";
import "./org_viewer.scss";
export class OrgEventsViewer extends React.Component {
    shouldComponentUpdate(nextProps) {
        if (this.props.content !== nextProps.content) return true;
        if (this.props.isActive !== nextProps.isActive) return true;
        return false;
    }
    render() {
        const headlines = this.props.isActive ? extractEvents(this.props.content) : [];
        return (
             
        );
    }
}
export class OrgTodosViewer extends React.Component {
    shouldComponentUpdate(nextProps) {
        if (this.props.content !== nextProps.content) return true;
        if (this.props.isActive !== nextProps.isActive) return true;
        return false;
    }
    render() {
        const headlines = this.props.isActive ? extractTodos(this.props.content) : [];
        return (
             
        );
    }
}
class OrgViewer extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            headlines: this.buildHeadlines(props.headlines),
            content: props.content,
            search: "",
            _: null,
        };
        this.rerender = () => this.setState({ _: randomString() });
        this.findResults = debounce(this.findResults.bind(this), 150);
    }
    UNSAFE_componentWillReceiveProps(props) {
        this.setState({
            headlines: this.buildHeadlines(props.headlines),
            content: props.content,
        });
    }
    buildHeadlines(headlines) {
        return headlines
            .reduce((acc, headline) => {
                if (!acc[headline["key"]]) {
                    acc[headline["key"]] = [];
                }
                acc[headline["key"]].push(headline);
                return acc;
            }, {});
    }
    onChange(i, j, state) {
        const headlines = { ...this.state.headlines };
        headlines[Object.keys(this.state.headlines)[i]][j].status = state;
        this.setState({
            headlines: this.state.headlines,
        });
    }
    onTaskUpdate(type, line, value) {
        const content = this.state.content.split("\n");
        let head_line;
        let item_line;
        let head_status;
        let deadline_line;
        let scheduled_line;
        let insertion_line;
        switch (type) {
        case "status":
            content[line] = content[line].replace(/^(\*+\s)[A-Z]{3,}(\s.*)$/, "$1"+value+"$2");
            break;
        case "subtask":
            if (value === "DONE") {
                content[line] = content[line].replace(/\[.\]/, "[X]");
            } else {
                content[line] = content[line].replace(/\[.\]/, "[ ]");
            }
            break;
        case "existing_scheduled":
            [head_line, head_status, item_line] = line;
            content[item_line] = content[item_line].replace(/SCHEDULED: <.*?>\s*/, value ? "SCHEDULED: "+orgdate(value)+" " : "");
            this.state.headlines[head_status] = this.state.headlines[head_status]
                .map((todo) => {
                    if (todo.line === head_line) {
                        if (value) todo.scheduled.timestamp = new Date(value).toISOString();
                        else todo.scheduled = null;
                    }
                    return todo;
                });
            this.setState({ headlines: this.state.headlines });
            break;
        case "existing_deadline":
            [head_line, head_status, item_line] = line;
            content[item_line] = content[item_line].replace(/DEADLINE: <.*?>\s*/, value ? "DEADLINE: "+orgdate(value) : "");
            this.state.headlines[head_status] = this.state.headlines[head_status]
                .map((todo) => {
                    if (todo.line === head_line) {
                        if (value) todo.deadline.timestamp = new Date(value).toISOString();
                        else todo.deadline = null;
                    }
                    return todo;
                });
            this.setState({ headlines: this.state.headlines });
            break;
        case "new_scheduled":
            [head_line, head_status, deadline_line] = line;
            if (deadline_line !== null) {
                insertion_line = deadline_line;
                content[deadline_line] = "SCHEDULED: "+orgdate(value)+" "+content[deadline_line];
            } else {
                insertion_line = head_line + 1;
                if (content[insertion_line] === "" && content[insertion_line + 1] === "") {
                    content[insertion_line] = "SCHEDULED: "+orgdate(value);
                } else {
                    content.splice(
                        insertion_line,
                        0,
                        "SCHEDULED: "+orgdate(value),
                    );
                }
            }
            this.state.headlines[head_status] = this.state.headlines[head_status]
                .map((todo) => {
                    if (todo.line === head_line) {
                        todo.scheduled = {
                            line: insertion_line,
                            keyword: "SCHEDULED",
                            active: true,
                            range: null,
                            repeat: null,
                            timestamp: new Date(value).toISOString(),
                        };
                    }
                    return todo;
                });
            this.setState({ headlines: this.state.headlines });
            break;
        case "new_deadline":
            [head_line, head_status, scheduled_line] = line;
            if (scheduled_line !== null) {
                insertion_line = scheduled_line;
                content[scheduled_line] = content[scheduled_line]+" DEADLINE: "+orgdate(value);
            } else {
                insertion_line = head_line + 1;
                if (content[insertion_line] === "" && content[insertion_line + 1] === "") {
                    content[insertion_line] = "DEADLINE: "+orgdate(value);
                } else {
                    content.splice(
                        insertion_line,
                        0,
                        "DEADLINE: "+orgdate(value),
                    );
                }
                this.state.headlines[head_status] = this.state.headlines[head_status]
                    .map((todo) => {
                        if (todo.line === head_line) {
                            todo.deadline = {
                                line: insertion_line,
                                keyword: "DEADLINE",
                                active: true,
                                range: null,
                                repeat: null,
                                timestamp: new Date(value).toISOString(),
                            };
                        }
                        return todo;
                    });
                this.setState({ headlines: this.state.headlines });
            }
            break;
        }
        this.setState({ content: content.join("\n") });
        function orgdate(_date) {
            const date = new Date(_date);
            return "<"+date.getFullYear()+"-"+leftPad((date.getMonth() + 1).toString(), 2)+"-"+leftPad(date.getDate().toString(), 2)+" "+day(date.getDay())+">";
            function day(n) {
                switch (navigator.language.split("-")[0]) {
                case "de": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"][n];
                    break;
                default: return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][n];
                }
            }
        }
    }
    navigate(line) {
        this.props.goTo(line);
        this.onQuit();
    }
    onQuit() {
        this.props.onUpdate(this.state.content);
        this.props.onQuit();
    }
    componentDidMount() {
        window.addEventListener("resize", this.rerender);
    }
    componentWillUnmount() {
        window.removeEventListener("resize", this.rerender);
    }
    search(terms) {
        this.setState({ search: terms }, () => {
            this.findResults(terms);
        });
    }
    findResults(terms) {
        let headlines = this.props.headlines;
        if (terms) {
            headlines = this.props.headlines.filter((headline) => {
                const keywords = terms.split(" ");
                const head = function() {
                    let str = " ";
                    str += headline["status"] + " ";
                    str += headline["title"] + " ";
                    str += headline.tags.map((tag) => "#"+tag).join(" ") + " ";
                    str += headline.scheduled ? "scheduled "+headline.scheduled.timestamp + " ": "";
                    str += headline.deadline ? "deadline "+headline.deadline.timestamp + " ": "";
                    str += headline.priority ? "priority #"+headline.priority+" " : "";
                    str += headline.is_overdue ? "overdue " : "";
                    str += headline.tasks.map((task) => task.title).join(" ")+ " ";
                    return str;
                }(headline);
                return keywords.filter((keyword) => new RegExp(" "+keyword, "i").test(head)).length === keywords.length ? true : false;
            });
        }
        this.setState({ headlines: this.buildHeadlines(headlines) });
    }
    render() {
        return (
            
                
                    
                         
                     
                    
{this.props.title} 
                     0}>
                         0 ? "active" : ""}>
                              this.search(e.target.value)} placeholder={t("Search")+" ..."}/>
                             
                         
                     
                 
                
                    { t("empty") }
                 
                 0}>
                     750 ? 545 : window.innerHeight - 202 }}>
                        {
                            Object.keys(this.state.headlines).map((list, i) => {
                                return (
                                    
                                        
                                            {
                                                ({ style }) => {
                                                    return (
                                                        
                                                            
{list} {this.state.headlines[list].length}  
                                                        
                                                    );
                                                }
                                            }
                                         
                                        
                                            {
                                                this.state.headlines[list].map((headline, j) => {
                                                    return (
                                                         
                                                    );
                                                })
                                            }
                                        
                                     
                                );
                            })
                        }
                     
                 
            
        );
    }
}
class Headline extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            status: props.todo_status,
            properties: false,
        };
    }
    onMenuAction(key) {
        if (key === "navigate") {
            this.props.goTo();
        } else if (key === "properties") {
            this.setState({ properties: !this.state.properties });
        }
    }
    onStatusToggle() {
        if (!this.props.todo_status) return;
        const new_status = this.state.status === "todo" ? "done" : "todo";
        this.setState({ status: new_status });
        const new_status_label = function(new_status, initial_status, initial_keyword) {
            if (new_status === initial_status) return initial_keyword;
            return new_status === "todo" ? "TODO" : "DONE";
        }(new_status, this.props.todo_status, this.props.status);
        this.props.onTaskUpdate("status", this.props.line, new_status_label);
    }
    onTimeSet(keyword, existing, value) {
        if (existing === true) {
            this.props.onTaskUpdate(
                "existing_"+keyword,
                [
                    this.props.line,
                    this.props.sortKey,
                    this.props[keyword].line,
                ],
                value,
            );
        } else {
            const opposite_keyword = keyword === "scheduled" ? "deadline" : "scheduled";
            this.props.onTaskUpdate(
                "new_"+keyword,
                [
                    this.props.line,
                    this.props.sortKey,
                    this.props[opposite_keyword] && this.props[opposite_keyword].line || null,
                ],
                value,
            );
        }
    }
    render() {
        const dateInput = (obj) => {
            if (!obj || !obj.timestamp) return "";
            const d = new Date(obj.timestamp);
            return d.getFullYear()+"-"+leftPad((d.getMonth() + 1).toString(), 2)+"-"+leftPad(d.getDate().toString(), 2);
        };
        return (
            
                
                    
                        
                            {this.props.title} 
                            
                                 
                             
                            
                                 
                             
                            
                                {
                                    this.props.tags.map((tag, i) => {
                                        return (
                                            {tag} 
                                        );
                                    })
                                }
                            
                         
                     
                    
                        
                             
                         
                        
                             { t("Navigate") }  
                             { t("Properties") }  
                         
                     
                 
                
                    
                          
                            
                                  this.onTimeSet("scheduled", true, e.target.value)}/>
                             
                            
                                  this.onTimeSet("scheduled", false, e.target.value)}/>
                             
                         
                    
                    
                          
                            
                                  this.onTimeSet("deadline", true, e.target.value)}/>
                             
                            
                                  this.onTimeSet("deadline", false, e.target.value)}/>
                             
                         
                    
                 
                 0 && this.state.status === "todo" && this.props.type === "todos"} className="subtask_container">
                    {
                        this.props.tasks.map((task, i) => {
                            return (
                                 
                            );
                        })
                    }
                 
             
        );
    }
}
class Subtask extends React.Component {
    constructor(props) {
        super(props);
        this.state = this.calculateState();
    }
    calculateState() {
        return { checked: this.props.status === "DONE" };
    }
    updateState(e) {
        const checked = e.target.checked;
        this.setState({ checked: checked }, () => {
            // We don't want the interface to feel laggy while a task is beeing updated. Updating
            // the content and reparsing the result is an expensive operation, this makes it feel
            // like a piece of cake
            window.setTimeout(() => {
                window.requestAnimationFrame(() => {
                    this.props.onStatusChange(checked ? "DONE" : "TODO");
                });
            }, 0);
        });
    }
    render() {
        return (
            
                
                     
                    {this.props.label} 
                 
            
        );
    }
}