text: /* 
  This is a budget web app that is made completely in HTML, 
  CSS, and JS and is intended for learning purposed only.
  
  Code is based on the budget app from The Complete JavaScript 
  Course 2019: Build Real Projects! course on Udemy which can be 
  found here: https://www.udemy.com/share/101WfeBkcfeV1XQnQ=/
  
  DISCLAIMER: This is for personal learning purposes only. I am not 
  responsible for any miscalculations, incorrect calculations, or any 
  incorrect number values shown while using this app.
  */
  
  // Budget Controller
  const budgetController = (() => {
  
      // Does not like arrow functions because the 'this' needs to have its own scope. NOT the window object
      const Expense = function (id, description, value) {
          this.id = id;
          this.description = description
          this.value = value;
          this.percentage = -1;
      };
  
      Expense.prototype.calcPercentage = function (totalIncome) {
          if (totalIncome > 0) {
              //console.log(this.percentage)
              this.percentage = Math.round((this.value / totalIncome) * 100);
          } else {
              this.percentage = -1;
          }
      };
  
      Expense.prototype.getPercentage = function () {
          return this.percentage;
      };
  
      const Income = function (id, description, value) {
          this.id = id;
          this.description = description
          this.value = value;
      };
  
      const calculateTotal = (type) => {
          let sum = 0;
  
          data.allItems[type].forEach((cur) => {
              sum += cur.value;
          })
  
          data.totals[type] = sum;
  
      };
  
      const data = {
          allItems: {
              exp: [],
              inc: []
          },
          totals: {
              exp: 0,
              inc: 0
          },
          budget: 0,
          percentage: -1
      };
  
      return {
          addItem: (type, des, val) => {
              let newItem, ID;
  
              // Create new ID
              if (data.allItems[type].length > 0) {
                  ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
              } else {
                  ID = 0;
              }
  
              // Create new item based on 'inc' or 'exc' type
              if (type === 'exp') {
                  newItem = new Expense(ID, des, val);
              } else {
                  newItem = new Income(ID, des, val);
              }
  
              // Push it into our data structures
              data.allItems[type].push(newItem);
  
              // Return the new element
              return newItem;
          },
  
          deleteItem: (type, id) => {
              let ids = data.allItems[type].map((cur) => {
                  return cur.id
              });
  
              index = ids.indexOf(id);
  
              if (index !== -1) {
                  data.allItems[type].splice(index, 1);
              }
          },
  
          calculateBudget: () => {
              // Calculate total income and expenses
              calculateTotal('exp');
              calculateTotal('inc');
  
              // Calculate the budget: income - expenses
              data.budget = data.totals.inc - data.totals.exp;
  
              // Calculate the percentage of income that we spent
              if (data.totals.inc > 0) {
                  data.percentage = Math.round((data.totals.exp / data.totals.inc) * 100);
              } else {
                  data.percentage = -1;
              }
          },
  
          calculatePercentages: () => {
              data.allItems.exp.forEach((cur) => {
                  cur.calcPercentage(data.totals.inc);
              })
  
          },
  
          getPercentages: () => {
              let allPerc = data.allItems.exp.map((cur) => {
                  return cur.getPercentage();
              });
              return allPerc;
          },
  
          getBudget: () => {
              return {
                  budget: data.budget,
                  totalInc: data.totals.inc,
                  totalExp: data.totals.exp,
                  percentage: data.percentage
              }
          }
      };
  
  })();
  
  
  // UI Controller
  const UIController = (() => {
  
      const DOMstrings = {
          inputType: '.add__type',
          inputDescription: '.add__description',
          inputValue: '.add__value',
          inputBtn: '.add__btn',
          incomeContainer: '.income__list',
          expensesContainer: '.expenses__list',
          budgetLabel: '.budget__value',
          incomeLabel: '.budget__income--value',
          expenseLabel: '.budget__expenses--value',
          percentageLabel: '.budget__expenses--percentage',
          container: '.container',
          expensesPercLabel: '.item__percentage',
          dateLabel: '.budget__title--month'
  
      };
  
      let formatNumber = (num, type) => {
          num = Math.abs(num);
          num = num.toFixed(2);
  
          numSplit = num.split('.');
  
          int = numSplit[0];
  
          if (int.length > 3) {
              int = int.substr(0, int.length - 3) + ',' + int.substr(int.length - 3, int.length); // input 23510, output 23,510
          }
  
          dec = numSplit[1];
  
          return (type === 'exp' ? '-' : '+') + ' ' + int + '.' + dec;
      };
  
      let nodeListForEach = (list, callback) => {
          for (let i = 0; i < list.length; i++) {
              callback(list[i], i);
          }
      }
  
      return {
          getinput: () => {
              return {
                  type: document.querySelector(DOMstrings.inputType).value, // Will be either inc or exp
                  description: document.querySelector(DOMstrings.inputDescription).value,
                  value: parseFloat(document.querySelector(DOMstrings.inputValue).value) // Converts the string to a float
              }
          },
  
          addListItem: (obj, type) => {
              let html, newHtml, element;
              // Create HTML string with placeholder text
  
              if (type === 'inc') {
                  element = DOMstrings.incomeContainer;
                  html = '<div class="item clearfix" id="inc-%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>'
              } else {
                  element = DOMstrings.expensesContainer;
                  html = '<div class="item clearfix" id="exp-%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">21%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>'
              }
  
              // Replace the placeholder text
              newHtml = html.replace('%id%', obj.id);
              newHtml = newHtml.replace('%description%', obj.description);
              newHtml = newHtml.replace('%value%', formatNumber(obj.value, type));
  
              // Insert the HTML text
              document.querySelector(element).insertAdjacentHTML('beforeend', newHtml);
  
          },
  
          deleteListItem: (selectorID) => {
              let el = document.getElementById(selectorID);
              el.parentNode.removeChild(el);
          },
  
          clearFields: () => {
              let fields, fieldsArr;
  
              fields = document.querySelectorAll(DOMstrings.inputDescription + ', ' + DOMstrings.inputValue);
  
              fieldsArr = Array.prototype.slice.call(fields);
  
              fieldsArr.forEach((cur, index, array) => {
                  cur.value = "";
              });
  
              fieldsArr[0].focus();
          },
  
          displayBudget: (obj) => {
              let type;
              obj.budget > 0 ? type = 'inc' : type = 'exp';
  
              document.querySelector(DOMstrings.budgetLabel).textContent = formatNumber(obj.budget, type);
              document.querySelector(DOMstrings.incomeLabel).textContent = formatNumber(obj.totalInc, 'inc');
              document.querySelector(DOMstrings.expenseLabel).textContent = formatNumber(obj.totalExp, 'exp');
  
              if (obj.percentage > 0) {
                  document.querySelector(DOMstrings.percentageLabel).textContent = obj.percentage + '%';
              } else {
                  document.querySelector(DOMstrings.percentageLabel).textContent = '---'
              }
          },
  
          displayPercentages: (percentages) => {
  
              let fields = document.querySelectorAll(DOMstrings.expensesPercLabel);
  
              nodeListForEach(fields, (cur, index) => {
  
                  if (percentages[index] > 0) {
                      cur.textContent = percentages[index] + '%';
                  } else {
                      cur.textContent = '---';
                  }
              });
  
          },
  
          displayMonth: () => {
              let now, year, month, months;
  
              months = [
                  'January',
                  'February',
                  'March',
                  'April',
                  'May',
                  'June',
                  'July',
                  'August',
                  'September',
                  'October',
                  'November',
                  'December'
              ];
  
              now = new Date();
  
              month = now.getMonth();
  
              year = now.getFullYear();
              document.querySelector(DOMstrings.dateLabel).textContent = months[month] + ' ' + year;
          },
  
          changedType: () => {
              let fields = document.querySelectorAll(
                  DOMstrings.inputType + ',' +
                  DOMstrings.inputDescription + ',' +
                  DOMstrings.inputValue);
  
              nodeListForEach(fields, (cur) => {
                  cur.classList.toggle('red-focus');
              })
  
              document.querySelector(DOMstrings.inputBtn).classList.toggle('red');
  
          },
  
          getDOMstrings: () => {
              return DOMstrings;
          }
      };
  
  })();
  
  
  // Global App Controller
  const controller = ((budgetCtrl, UICtrl) => {
  
      const setupEventListeners = () => {
          const DOM = UICtrl.getDOMstrings();
  
          document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);
  
          document.addEventListener('keypress', (event) => {
              if (event.keyCode === 13 || event.which === 13) {
                  ctrlAddItem();
              }
          });
  
          document.querySelector(DOM.container).addEventListener('click', ctrlDeleteItem);
  
          document.querySelector(DOM.inputType).addEventListener('change', UICtrl.changedType);
      }
  
      const updateBudget = () => {
          // 1. Calculate the budget
          budgetCtrl.calculateBudget();
  
          // 2. Return the budget
          const budget = budgetCtrl.getBudget();
  
  
          // 3. Display the budget on the UI
          UICtrl.displayBudget(budget);
  
      };
  
      const updatePercentages = () => {
  
          // 1. Calculate percentages
          budgetCtrl.calculatePercentages();
  
          // 2. Read percentages from the budget controller
          let percentages = budgetCtrl.getPercentages();
  
          // 3. Update the UI with the new percentages
          UICtrl.displayPercentages(percentages);
  
      };
  
      const ctrlAddItem = () => {
  
          let input, newItem;
  
          // 1. Get the filled input data
          input = UIController.getinput();
  
          if (input.description !== "" && !isNaN(input.value) && input.value > 0) { // Makes sure the inputs are NOT empty
  
              // 2. Add the item to the budget controller
              newItem = budgetCtrl.addItem(input.type, input.description, input.value)
  
              // 3. Add the item to the UI
              UICtrl.addListItem(newItem, input.type);
              UICtrl.clearFields()
  
              // 4. Calculate and update budget
              updateBudget();
  
              // 5. Calculate and update percentages
              updatePercentages();
          }
      };
  
      const ctrlDeleteItem = (event) => {
          let itemID;
  
          itemID = event.target.parentNode.parentNode.parentNode.parentNode.id;
  
          if (itemID) {
  
              splitID = itemID.split('-');
              type = splitID[0];
              ID = parseInt(splitID[1]);
  
              // 1. delete the item from the data structure
              budgetCtrl.deleteItem(type, ID);
  
              // 2. Delete the item from the UI
              UICtrl.deleteListItem(itemID);
  
              // 3. Update and show the new budget
              updateBudget();
  
              // 4. Calculate and update percentages
              updatePercentages();
  
          }
      }
  
      return {
          init: () => {
              console.log('Started')
              UICtrl.displayMonth();
              UICtrl.displayBudget({
                  budget: 0,
                  totalInc: 0,
                  totalExp: 0,
                  percentage: -1
              });
              setupEventListeners();
          }
      }
  
  })(budgetController, UIController);
  
  controller.init()
  