text: // IMPORT ALL THE THINGS NEEDED FROM OTHER JAVASCRIPT SOURCE FILES
  import React, { Component } from 'react';
  import testData from './test/testData.json'
  import jsTPS from './common/jsTPS_Transaction'
  
  // THESE ARE OUR REACT COMPONENTS
  import Navbar from './components/Navbar'
  import LeftSidebar from './components/LeftSidebar'
  import Workspace from './components/Workspace'
  import DeleteModal from './components/DeleteModal';
  import AddNewItem_Transaction from './transactions/AddNewItem_Transaction';
  import DeleteItem_Transaction from './transactions/DeleteItem_Transaction';
  import ChangeTaskText_Transaction from './transactions/ChangeTaskText_Transaction';
  import ChangeDueDate_Transaction from './transactions/ChangeDueDate_Transaction';
  import ChangeStatus_Transaction from './transactions/ChangeStatus_Transaction';
  import ShiftItemUp_Transaction from './transactions/ShiftItemUp_Transaction';
  import ShiftItemDown_Transaction from './transactions/ShiftItemDown_Transaction';
  {/*import ItemsListHeaderComponent from './components/ItemsListHeaderComponent'
  import ItemsListComponent from './components/ItemsListComponent'
  import ListsComponent from './components/ListsComponent'
  */}
  class App extends Component {
    constructor(props) {
      // ALWAYS DO THIS FIRST
      super(props);
  
      // DISPLAY WHERE WE ARE
      // console.log("App constructor");
  
      // MAKE OUR TRANSACTION PROCESSING SYSTEM
      this.tps = new jsTPS();
  
      // CHECK TO SEE IF THERE IS DATA IN LOCAL STORAGE FOR THIS APP
      let recentLists = localStorage.getItem("recentLists");
      // console.log("recentLists: " + recentLists);
      if (!recentLists) {
        recentLists = JSON.stringify(testData.toDoLists);
        localStorage.setItem("toDoLists", recentLists);
      }
      recentLists = JSON.parse(recentLists);
  
      // FIND OUT WHAT THE HIGHEST ID NUMBERS ARE FOR LISTS
      let highListId = -1;
      let highListItemId = -1;
      for (let i = 0; i < recentLists.length; i++) {
        let toDoList = recentLists[i];
        if (toDoList.id > highListId) {
          highListId = toDoList.id;
        }
        for (let j = 0; j < toDoList.items.length; j++) {
          let toDoListItem = toDoList.items[j];
          if (toDoListItem.id > highListItemId)
          highListItemId = toDoListItem.id;
        }
      };
  
  
      // SETUP OUR APP STATE
      this.state = {
        toDoLists: recentLists,
        currentList: {
          items: []
        },
        currentListId: -1,
        currentItemId: -1,
        nextListId: highListId+1,
        nextListItemId: highListItemId+1,
        useVerboseFeedback: true,
        showDeletePopup: false,
        isTaskText: true,
        isDateText: true,
        isStatusText: true,
        isListText: true,
        ctrl: false,
        z: false,
        y: false
      }
    }
  
    addItemCallback = () => {
      let newItem = this.addNewItem();
      let newList = this.state.currentList;
      newList.items.push(newItem);
      this.setState({
        currentList: newList,
        nextListItemId: this.state.nextListItemId+1
      }, this.afterToDoListsChangeComplete);
      return newItem;
    }
  
    addNewItemTransaction = () => {
      let transaction = new AddNewItem_Transaction(this);
      this.tps.addTransaction(transaction);
    }
  
    addNewItem = () =>  {
      let newToDoListItem = {
        id: this.state.nextListItemId,
        description: "No Description",
        due_date: "No Date",
        status: "incomplete"
      };
      return newToDoListItem;
    }
  
    addItemAtPosition = (item, index) => {
      let list = this.state.currentList;
      list.items.splice(index, 0, item);
      this.setState({
        currentList: list
      }, this.afterToDoListsChangeComplete);
    }
  
    deleteItemTransaction = (item, index) => {
      let transaction = new DeleteItem_Transaction(this, item, index);
      this.tps.addTransaction(transaction);
    }
  
    deleteItemCallback = (itemId) => {
      let indexOfItem = -1;
      let list = this.state.currentList;
      for (let i = 0; (i < list.items.length) && (indexOfItem < 0); i++) {
          if (list.items[i].id === itemId) {
              indexOfItem = i;
          }
      }
      list.items.splice(indexOfItem, 1);
      this.setState({
        currentList: list
      }, this.afterToDoListsChangeComplete);
    }
  
    // WILL LOAD THE SELECTED LIST
    loadToDoList = (toDoList) => {
      // MAKE SURE toDoList IS AT THE TOP OF THE STACK BY REMOVING THEN PREPENDING
      const nextLists = this.state.toDoLists.filter(testList =>
        testList.id !== toDoList.id
      );
      nextLists.unshift(toDoList);
  
      this.setState({
        toDoLists: nextLists,
        currentList: toDoList,
        currentListId: toDoList.id
      }, this.afterToDoListsChangeComplete);
    }
  
    addNewList = () => {
      let newToDoListInList = [this.makeNewToDoList()];
      let newToDoListsList = [...this.state.toDoLists, ...newToDoListInList];
      let newToDoList = newToDoListInList[0];
      // AND SET THE STATE, WHICH SHOULD FORCE A render
      this.setState({
        toDoLists: newToDoListsList,
        currentList: newToDoList,
        nextListId: this.state.nextListId+1
      }, this.afterToDoListsChangeComplete)
      this.loadToDoList(newToDoList);
    }
  
    makeNewToDoList = () => {
      let newToDoList = {
        id: this.state.nextListId,
        name: 'Untitled',
        items: []
      };
      return newToDoList;
    }
  
  
    // THIS IS A CALLBACK FUNCTION FOR AFTER AN EDIT TO A LIST
    afterToDoListsChangeComplete = () => {
      console.log("App updated currentToDoList: ");
      console.log(this.state.currentList);
  
      // WILL THIS WORK? @todo
      let toDoListsString = JSON.stringify(this.state.toDoLists);
      localStorage.setItem("recentLists", toDoListsString);
    }
  
    viewDeletePopup = () => {
      this.setState({
        showDeletePopup: true
      })
    }
  
    closeList = () => {
      this.tps.clearAllTransactions();
      this.setState({
        currentList: {items: []},
        currentListId: -1
      }, this.afterToDoListsChangeComplete)
    }
  
    shouldDeleteListCallback = (cond) => {
      if (cond === "yes"){
        const lists = this.state.toDoLists.filter(testList =>
          testList.id !== this.state.currentListId
        );
        this.setState({
          toDoLists: lists,
          showDeletePopup: false,
          currentList: {items: []},
          currentListId: -1
        }, this.afterToDoListsChangeComplete);
      } else {
        this.setState({
          showDeletePopup: false
        }, this.afterToDoListsChangeComplete)
      }
    }
  
    shiftItemUpTransaction = (itemId) => {
      let transaction = new ShiftItemUp_Transaction(this, itemId);
      this.tps.addTransaction(transaction);
    }
  
    moveItemUpCallback = (itemId) => {
      let itemIndex = -1;
      let list = this.state.currentList;
      for (let i = 0; (i < list.items.length) && (itemIndex < 0); i++){
          if (list.items[i].id === itemId)
              itemIndex = i;
      }
      if (itemIndex >= 1) {
          let tmp = list.items[itemIndex - 1];
          list.items[itemIndex - 1] = list.items[itemIndex];
          list.items[itemIndex] = tmp;
      }
      this.setState({
        currentList: list
      }, this.afterToDoListsChangeComplete)
    }
  
    shiftItemDownTransaction = (itemId) => {
      let transaction = new ShiftItemDown_Transaction(this, itemId);
      this.tps.addTransaction(transaction);
    }
  
    moveItemDownCallback = (itemId) => {
      let itemIndex = -1;
      let list = this.state.currentList;
      for (let i = 0; (i < list.items.length) && (itemIndex < 0); i++){
          if (list.items[i].id === itemId)
              itemIndex = i;
      }
      if (itemIndex >= 0 && itemIndex < list.items.length - 1) {
          let tmp = list.items[itemIndex + 1];
          list.items[itemIndex + 1] = list.items[itemIndex];
          list.items[itemIndex] = tmp;
      }
      this.setState({
        currentList: list
      }, this.afterToDoListsChangeComplete)
    }
  
    undo = () => {
      if (this.tps.hasTransactionToUndo()) {
        this.tps.undoTransaction();
      }
    }
  
    redo = () => {
      if (this.tps.hasTransactionToRedo()) {
        this.tps.doTransaction();
      }
    }
  
    changeTaskTransaction = (itemId, text, oldValue) => {
      let transaction = new ChangeTaskText_Transaction(this, itemId, text, oldValue);
      this.tps.addTransaction(transaction);
    }
  
    changeTaskToInputCallback = (itemId) => {
      this.setState({
        isTaskText: false,
        currentItemId: itemId
      });
    }
  
    changeTaskToTextCallback = (itemId, text) => {
      let itemIndex = -1;
      let list = this.state.currentList;
      for (let i = 0; (i < list.items.length) && (itemIndex < 0); i++){
          if (list.items[i].id === itemId)
              itemIndex = i;
      }
      if (itemIndex >= 0){
          list.items[itemIndex].description = text;
      }
      this.setState({
        isTaskText: true,
        currentItemId: -1,
      }, this.afterToDoListsChangeComplete); 
    }
  
    changeDateTransaction = (itemId, value, oldValue) => {
      let transaction = new ChangeDueDate_Transaction(this, itemId, value, oldValue);
      this.tps.addTransaction(transaction);
    }
  
    changeDateToInputCallback = (itemId) => {
      this.setState({
        isDateText: false,
        currentItemId: itemId
      }); 
    }
  
    changeDateToTextCallback = (itemId, date) => {
      let itemIndex = -1;
      let list = this.state.currentList;
      for (let i = 0; (i < list.items.length) && (itemIndex < 0); i++){
          if (list.items[i].id === itemId)
              itemIndex = i;
      }
      if (itemIndex >= 0){
          list.items[itemIndex].due_date = date;
      }
      this.setState({
        isDateText: true,
        currentItemId: -1
      }, this.afterToDoListsChangeComplete);
    }
  
    changeStatusTransaction = (itemId, status, oldValue) => {
      let transaction = new ChangeStatus_Transaction(this, itemId, status, oldValue);
      this.tps.addTransaction(transaction);
    }
  
    changeStatusToInputCallback = (itemId) => {
      this.setState({
        isStatusText: false,
        currentItemId: itemId
      }); 
    }
  
    changeStatusToTextCallback = (itemId, status) => {
      let itemIndex = -1;
      let list = this.state.currentList;
      for (let i = 0; (i < list.items.length) && (itemIndex < 0); i++){
          if (list.items[i].id === itemId)
              itemIndex = i;
      }
      if (itemIndex >= 0){
          list.items[itemIndex].status = status;
      }
      this.setState({
        isStatusText: true,
        currentItemId: -1
      }, this.afterToDoListsChangeComplete); 
    }
  
    componentDidMount = () => {
      document.onkeydown = (e) => {
        if (e.key === 'Control') {
          this.setState({
            ctrl: true
          })
        } 
        if (e.key === 'y') {
          if (this.state.ctrl) this.redo();
          this.setState({
            y: true
          })
        } 
        if (e.key === 'z') {
          if (this.state.ctrl) this.undo();
          this.setState({
            z: true
          })
        } 
      }
      document.onkeyup = (e) => {
        if (e.key === 'Control') {
          this.setState({
            ctrl: false
          })
        } 
        if (e.key === 'y') {
          this.setState({
            y: false
          })
        } 
        if (e.key === 'z') {
          this.setState({
            z: false
          })
        } 
      }
    }
  
    changeListToInputCallback = () => {
      this.setState({
        isListText: false,
      }, this.afterToDoListsChangeComplete); 
    }
  
    changeListToTextCallback = (name) => {
      let lists = this.state.toDoLists;
      lists[0].name = name;
      this.setState({
        isListText: true,
      }, this.afterToDoListsChangeComplete); 
    }
  
    render() {
      // console.log(this.tps.transactions);
      let items = this.state.currentList.items;
      
      return (
        <div id="base">
          <Navbar />
          <LeftSidebar 
            toDoLists={this.state.toDoLists}
            currentList={this.state.currentList}
            loadToDoListCallback={this.loadToDoList}
            addNewListCallback={this.addNewList}
            highlightCallback={this.highlight}
            undo={this.undo}
            redo={this.redo}
            canUndo={this.tps.hasTransactionToUndo()}
            canRedo={this.tps.hasTransactionToRedo()}
            isListText={this.state.isListText}
            changeListToTextCallback={this.changeListToTextCallback}
            changeListToInputCallback={this.changeListToInputCallback}
          />
          <Workspace 
            toDoListItems={items}
            currentListId={this.state.currentListId}
            currentItemId={this.state.currentItemId}
            addItemCallback={this.addNewItemTransaction}
            deletePopupCallback={this.viewDeletePopup}
            closeListCallback={this.closeList}
            moveItemUpCallback={this.shiftItemUpTransaction}
            moveItemDownCallback={this.shiftItemDownTransaction}
            deleteItemCallback={this.deleteItemTransaction}
  
            isTaskText={this.state.isTaskText}
            isDateText={this.state.isDateText}
            isStatusText={this.state.isStatusText}
  
            changeTaskToTextCallback={this.changeTaskTransaction}
            changeTaskToInputCallback={this.changeTaskToInputCallback}
            changeDateToTextCallback={this.changeDateTransaction}
            changeDateToInputCallback={this.changeDateToInputCallback}
            changeStatusToTextCallback={this.changeStatusTransaction}
            changeStatusToInputCallback={this.changeStatusToInputCallback}
          />
          <DeleteModal 
            shouldDeleteListCallback={this.shouldDeleteListCallback}
            delete={this.state.showDeletePopup}
          />
        </div>
  
  
      );
    }
  }
  
  
  export default App;