text: from typing import Union, Tuple, List, TYPE_CHECKING
  from abc import ABC, abstractmethod
  
  from .defaults import DEFAULT_SECTION_CONFIG
  
  
  class Section:
      """ Interface for section object
      includes methods that are specific to section
      like __iter__ 
  
      """
  
      def __init__(self):
          # need to implement your own section
          self.section = None
  
          # type of object that can be added to section
          self.supported_type = None
  
      def add(self):
          raise NotImplementedError
  
      def __iter__(self):
          raise NotImplementedError
  
  
  class BaseSectionAttacher:
      # interface with methods that will be added
      # directly to main object.
      #
      def __init__(self, section_type: str = None):
          self.section = None
          self.section_control = None
  
      def section_controller_factory(self):
          raise NotImplementedError
  
      def section_factory(self):
          raise NotImplementedError
  
      def add(self):
          raise NotImplementedError
  
  
  class SectionAttacher(Section, BaseSectionAttacher):
      """
      Abstract Factory Pattern
  
      SectionAttacher is both of type Section and SectionAttacher class.
  
      Allows child to attach or change to different Section types dynamically
      without knowing the name of New Section type.
      By default, all related classes will use the same Section type
  
      Classes using Section and SectionAttacher: Zig, DomElement, HtmlElement
  
  
      :param section_type: allows different object to choose
                          different implementation of Section.
      """
  
      def __init__(self, *args, section_type: str = DEFAULT_SECTION_CONFIG, **kwargs):
  
          if not hasattr(self, "section_control"):
              self.section = self.section_controller_factory(section_type)
  
          """
          if not hasattr(self, "section") and self.section_control:
              # creates section object
              self.section = self.section_factory(self.section_control)
              print(self.section)
          """
  
      def section_controller_factory(self, section_type: str):
          if SECTION_OPTIONS.get(section_type):
              return SECTION_OPTIONS[section_type]()
  
          raise Exception(f"Section Type {section_type} does not exist!")
  
      def section_factory(self, controller: Section):
          if controller:
              if hasattr(controller, "section"):
                  return controller.section
              else:
                  raise Exception(f"Controller doesn't have section")
          raise Exception(f"Requires Controller. {controller} is invalid")
  
      # Note: SectionAttacher needs to implement same method as Section
      # It works as a Factory and also an interface for the product
  
      def add(self, component: Section) -> None:
          if hasattr(self, "section"):
              self.section.add(component)
          else:
              raise Exception(f"Requires Section object")
          # so that it can be chained
          return self
  
      def insert(self):
          pass
  
      def show(self):
          if hasattr(self, "section"):
              self.section.show(self.section, *args, **kwargs)
          else:
              raise Exception(f"Requires Section object")
  
      def get(self, *args, **kwargs):
          if hasattr(self, "section"):
              self.section.get(self.section, *args, **kwargs)
          else:
              raise Exception(f"Requires Section object")
  
  
  # only for typing
  from .element import Element
  
  
  class CoreSection(Section):
      """ Backbone of all html element component that allows nesting.
      Main purpose of this class is to implement quick lookup and insert of component
  
      Section is used to contain other Section objects and non-section objects
  
  
      zig.section itself uses Section
  
      components are stored in dictionary with name/index as key
      components'name are stored in list to depict the order
      """
  
      def __init__(self):
  
          self.supported_type = Element
  
          # dictionary for fast retrievel
          self.__section_dict = {}
  
          # list to keep order; implementation of section and section_order need not be the same
          self.__section = self.__section_order = []
          self.order = 0
  
      @property
      def section(self):
          return self.__section
  
      @section.setter
      def section(self, var):
          # Section needs to maintain both hashmap and ordered list. Cannot be set manually.
          raise TypeError("Not able to set section manaully. Use section.add instead.")
  
      def add(self, component: Union[Element, List[Element]]):
          """
          add other components
          able to add one, or a list of components
  
          automate adding to dict, and list
          add(Div())
          add([Div(), Graph(), Div()])
          """
          if isinstance(component, list):
              for comp in component:
                  self.__section_order, self.__section_dict = self.__add(
                      comp, self.__section_order, self.__section_dict
                  )
          else:
              self.__add(component)
  
      def __add(
          self, component: Element, section_list: list, section_dict: dict
      ) -> Tuple[list, dict]:
          try:
              # try recording in hashtable first
              section_dict = self.__add_dict(component, section_dict)
          except Exception:
              raise
          else:
              try:
                  # then try adding to order
                  section_list = self.__add_to_order(component, section_list)
              except Exception:
                  raise e
  
          ## HOW TO MAKE SURE BOTH ARE UPDATED TOGETHER?
          return section_list, section_dict
  
      def __add_dict(self, component: Element, section_dict: dict) -> dict:
          if isinstance(component, self.supported_type):
              if section_dict.get(component.id):
                  # id already exist
                  raise Exception(f"id {component.id} is already in use")
              else:
                  # if given id, use it as key
                  if getattr(component, "id", None):
                      section_dict[component.id] = component
                  # else generate.
                  else:
                      # use order number as key
                      section_dict[self.order] = component
                      ## WHAT IF WE GENERATE SOMETHING THAT CLASHES WITH AN EXISTING ID?
  
                  self.order += 1
  
                  return section_dict
          else:
              raise TypeError(
                  f"Component {type(component)} need to be of type {self.supported_type}"
              )
  
      def __add_to_order(self, component: Element, section_list: list) -> list:
          if isinstance(component, self.supported_type):
              section_list.append(component)
              return section_list
          else:
              raise TypeError(
                  f"Component {type(component)} need to be of type {self.supported_type}"
              )
  
      def __iter__(self):
          for x in self.section:
              yield x
  
      def insert(self, index):
          # insert at index
          pass
  
      def show(self):
          # show all components in order
          return self.__section.dict
  
      def get(self, component_id):
          # return the specific component in the section
          return __section_dict.get(component_id, None)
  
  
  # this needs to be cleaner
  SECTION_OPTIONS = {"CoreSection": CoreSection}
  