refactor: ability to build and load tree from DB
diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js
index 69bd56e..732b2b0 100644
--- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js
+++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.js
@@ -14,15 +14,15 @@
 		frm.add_custom_button(__('Up'), () =>
 			frm.trigger("move_up")
 		);
-		frm.add_custom_button(__('Bisect'), () =>
-			frm.trigger("bisect")
+		frm.add_custom_button(__('Build Tree'), () =>
+			frm.trigger("build_tree")
 		);
 		// frm.change_custom_button_type(__('Bisect'), null, 'primary');
 	},
-	bisect(frm) {
+	build_tree(frm) {
 		frm.call({
 			doc: frm.doc,
-			method: 'bisect',
+			method: 'build_tree',
 			callback: (r) => {
 				console.log(r);
 			}
diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json
index b2f3c4b..e0b84ad 100644
--- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json
+++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.json
@@ -11,7 +11,14 @@
   "column_break_qxbi",
   "to_date",
   "column_break_iwny",
-  "algorithm"
+  "algorithm",
+  "section_break_lwr2",
+  "current_from_date",
+  "column_break_uuic",
+  "current_to_date",
+  "section_break_zbty",
+  "current_node",
+  "tree"
  ],
  "fields": [
   {
@@ -38,13 +45,45 @@
   {
    "fieldname": "column_break_iwny",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "section_break_zbty",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "tree",
+   "fieldtype": "JSON",
+   "label": "Tree"
+  },
+  {
+   "fieldname": "current_node",
+   "fieldtype": "JSON",
+   "label": "Current Node"
+  },
+  {
+   "fieldname": "section_break_lwr2",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "current_from_date",
+   "fieldtype": "Date",
+   "label": "Current From Date"
+  },
+  {
+   "fieldname": "current_to_date",
+   "fieldtype": "Date",
+   "label": "Current To Date"
+  },
+  {
+   "fieldname": "column_break_uuic",
+   "fieldtype": "Column Break"
   }
  ],
  "hide_toolbar": 1,
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2023-09-25 10:50:53.887235",
+ "modified": "2023-09-25 17:05:13.384320",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bisect Accounting Statements",
diff --git a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py
index 3582033..7c68f18 100644
--- a/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py
+++ b/erpnext/accounts/doctype/bisect_accounting_statements/bisect_accounting_statements.py
@@ -2,6 +2,7 @@
 # For license information, please see license.txt
 
 import datetime
+import json
 from collections import deque
 from math import floor
 
@@ -10,85 +11,162 @@
 from frappe import _
 from frappe.model.document import Document
 from frappe.utils import getdate
+from frappe.utils.data import DATETIME_FORMAT, guess_date_format
 
 
 class Node(object):
-	def __init__(self):
-		self.parent = None
-		self.left_child = None
-		self.right_child = None
-
-		self.current_period = None
-		self.difference = 0.0
-		self.profit_and_loss_summary = 0.0
-		self.balance_sheet_summary = 0.0
-
-	def update_parent(self):
-		pass
-
-	def update_left_child(self):
-		pass
-
-	def update_right_child(self):
-		pass
-
-	def make_node(
+	def __init__(
 		self,
 		parent: int = None,
 		period: (datetime, datetime) = None,
 		left: int = None,
 		right: int = None,
 	):
-		current_period = period
+		self.parent = parent
+		self.left_child = left
+		self.right_child = right
+
+		self.period = period
+		self.difference = 0.0
+		self.profit_and_loss_summary = 0.0
+		self.balance_sheet_summary = 0.0
+
+	def as_dict(self):
+		return dict(
+			parent=self.parent,
+			left_child=self.left_child,
+			right_child=self.right_child,
+			period=(self.period[0].strftime(DATETIME_FORMAT), self.period[1].strftime(DATETIME_FORMAT)),
+			difference=self.difference,
+			profit_and_loss_summary=self.profit_and_loss_summary,
+			balance_sheet_summary=self.balance_sheet_summary,
+		)
+
+	def __repr__(self):
+		return f"Node (parent: {self.parent}, left_child: {self.left_child}, right_child: {self.right_child}, period: {self.period})"
+
+
+class BTree(object):
+	def __init__(self):
+		self.btree = []
+		self.current_node = None
+
+	def as_list(self):
+		lst = []
+		for x in self.btree:
+			lst.append(x.as_dict())
+		return lst
+
+	def bfs(self, from_date: datetime, to_date: datetime):
+		root_node = Node(parent=None, period=(getdate(from_date), getdate(to_date)))
+		root_node.parent = None
+
+		# add root node to tree
+		self.btree.append(root_node)
+		cur_node = root_node
+		period_list = deque([root_node])
+
+		periods = []
+		while period_list:
+			cur_node = period_list.popleft()
+			cur_node_index = len(self.btree) - 1
+
+			delta = cur_node.period[1] - cur_node.period[0]
+			if delta.days == 0:
+				continue
+			else:
+				cur_floor = floor(delta.days / 2)
+				left = (cur_node.period[0], (cur_node.period[0] + relativedelta(days=+cur_floor)))
+				left_node = Node(parent=cur_node_index, period=left)
+				self.btree.append(left_node)
+				cur_node.left_child = len(self.btree) - 1
+				period_list.append(left_node)
+
+				right = ((cur_node.period[0] + relativedelta(days=+(cur_floor + 1))), cur_node.period[1])
+				right_node = Node(parent=cur_node_index, period=right)
+				self.btree.append(right_node)
+				cur_node.right_child = len(self.btree) - 1
+				period_list.append(right_node)
+
+	def dfs(self, from_date: datetime, to_date: datetime):
+		root_node = Node(parent=None, period=(getdate(from_date), getdate(to_date)))
+		root_node.parent = None
+
+		# add root node to tree
+		self.btree.append(root_node)
+		cur_node = root_node
+		period_list = [root_node]
+
+		periods = []
+		while period_list:
+			cur_node = period_list.pop()
+			cur_node_index = len(self.btree) - 1
+
+			delta = cur_node.period[1] - cur_node.period[0]
+			if delta.days == 0:
+				continue
+			else:
+				cur_floor = floor(delta.days / 2)
+				left = (cur_node.period[0], (cur_node.period[0] + relativedelta(days=+cur_floor)))
+				left_node = Node(parent=cur_node_index, period=left)
+				self.btree.append(left_node)
+				cur_node.left_child = len(self.btree) - 1
+				period_list.append(left_node)
+
+				right = ((cur_node.period[0] + relativedelta(days=+(cur_floor + 1))), cur_node.period[1])
+				right_node = Node(parent=cur_node_index, period=right)
+				self.btree.append(right_node)
+				cur_node.right_child = len(self.btree) - 1
+				period_list.append(right_node)
+
+	def load_tree(self, tree: list, current_node: dict):
+		self.btree = []
+		tree = json.loads(tree)
+		for x in tree:
+			x = frappe._dict(x)
+			n = Node(x.parent, x.period, x.left_child, x.right_child)
+			n.period = x.period
+			n.difference = x.difference
+			x.profit_and_loss_summary = x.profit_and_loss_summary
+			x.balance_sheet_summary = x.balance_sheet_summary
+			self.btree.append(n)
+
+		current_node = frappe._dict(json.loads(current_node))
+		n = Node(
+			current_node.parent, current_node.period, current_node.left_child, current_node.right_child
+		)
+		n.period = current_node.period
+		n.difference = current_node.difference
+		n.profit_and_loss_summary = current_node.profit_and_loss_summary
+		n.balance_sheet_summary = current_node.balance_sheet_summary
+		self.current_node = n
+
+	def build_tree(self, from_date: datetime, to_date: datetime, alogrithm: str):
+		if alogrithm == "BFS":
+			self.bfs(from_date, to_date)
+
+		if alogrithm == "DFS":
+			self.dfs(from_date, to_date)
+
+		# set root as current node
+		self.current_node = self.btree[0]
+
+	def bisec_left(self):
+		pass
+
+	def bisect_right(self):
+		pass
+
+	def move_up(self):
+		pass
 
 
 class BisectAccountingStatements(Document):
-	def bfs(self):
-		period_list = deque([(getdate(self.from_date), getdate(self.to_date))])
-		periods = []
-		dates = []
-		while period_list:
-			cur_frm_date, cur_to_date = period_list.popleft()
-			delta = cur_to_date - cur_frm_date
-			periods.append((cur_frm_date, cur_to_date, delta))
-			if delta.days == 0:
-				continue
-			else:
-				cur_floor = floor(delta.days / 2)
-				left = (cur_frm_date, (cur_frm_date + relativedelta(days=+cur_floor)))
-				right = ((cur_frm_date + relativedelta(days=+(cur_floor + 1))), cur_to_date)
-				period_list.append(left)
-				period_list.append(right)
-		return periods
-
-	def dfs(self):
-		period_list = [(getdate(self.from_date), getdate(self.to_date))]
-		periods = []
-		while period_list:
-			cur_frm_date, cur_to_date = period_list.pop()
-			delta = cur_to_date - cur_frm_date
-			periods.append((cur_frm_date, cur_to_date, delta))
-			if delta.days == 0:
-				continue
-			else:
-				cur_floor = floor(delta.days / 2)
-				left = (cur_frm_date, (cur_frm_date + relativedelta(days=+cur_floor)))
-				right = ((cur_frm_date + relativedelta(days=+(cur_floor + 1))), cur_to_date)
-				period_list.append(left)
-				period_list.append(right)
-		return periods
-
-	@frappe.whitelist()
-	def bisect(self):
-		if self.algorithm == "BFS":
-			periods = self.bfs()
-
-		if self.algorithm == "DFS":
-			periods = self.dfs()
-
-		print("Periods: ", len(periods))
-		for x in periods:
-			print(x)
+	def __init__(self, *args, **kwargs):
+		super(BisectAccountingStatements, self).__init__(*args, **kwargs)
+		if self.tree and self.current_node:
+			self.tree_instance = BTree()
+			self.tree_instance.load_tree(self.tree, self.current_node)
 
 	def validate(self):
 		self.validate_dates()
@@ -100,3 +178,18 @@
 					frappe.bold(self.from_date), frappe.bold(self.to_date)
 				)
 			)
+
+	@frappe.whitelist()
+	def build_tree(self):
+		self.tree_instance = BTree()
+		self.tree_instance.build_tree(self.from_date, self.to_date, self.algorithm)
+		print("printing tree")
+		for x in self.tree_instance.btree:
+			print(x)
+
+		print("Root", self.tree_instnace.current_node)
+
+		self.tree = json.dumps(self.tree_instance.as_list())
+		self.current_node = json.dumps(self.tree_intance.btree[0].as_dict())
+
+		print(guess_date_format(json.loads(self.current_node)["period"][0]))