(require 'polymode-common)

;;; ROOT CLASS
(defclass pm-root (eieio-instance-inheritor) ()
  "Root polymode class.")


;;; CONFIG
(defclass pm-polymode (pm-root) 
  ((hostmode
    :initarg :hostmode
    :initform 'pm-host/blank
    :type symbol
    :custom symbol
    :documentation
    "Symbol pointing to an object of class pm-chunkmode
    representing the host chunkmode.")
   (minor-mode
    :initarg :minor-mode
    :initform 'polymode-minor-mode
    :type symbol
    :custom symbol
    :documentation
    "Symbol pointing to minor-mode function that should be
    activated in all buffers (base and indirect). This is a
    \"glue\" mode and is `polymode-minor-mode' by default. You
    will rarely need to change this.")
   (lighter
    :initarg :lighter
    :initform " PM"
    :type string
    :custom string
    :documentation "Modline lighter.")
   (exporters
    :initarg :exporters
    :initform '(pm-exporter/pandoc)
    :type list
    :custom list
    :documentation
    "List of names of polymode exporters available for this polymode.")
   (exporter
    :initarg :exporter
    :initform nil
    :type (or null symbol)
    :custom symbol
    :documentation
    "Current exporter name. If non-nil should be the name of the
    default exporter for this polymode. Can be set with
    `polymode-set-exporter' command.")
   (weavers
    :initarg :weavers
    :initform '()
    :type list
    :custom list
    :documentation
    "List of names of polymode weavers available for this polymode.")
   (weaver
    :initarg :weaver
    :initform nil
    :type (or null symbol)
    :custom symbol
    :documentation
    "Current weaver name. If non-nil this is the default weaver
    for this polymode. Can be dynamically set with
    `polymode-set-weaver'")
   (map
    :initarg :map
    :initform 'polymode-mode-map
    :type (or symbol list)
    "Has a similar role as the :keymap argument in
     `define-polymode' with the difference that this argument is
     inherited through cloning, but :keymap argument is not. That
     is, child objects derived through clone will inherit
     the :map argument of its parents through the following
     scheme: if :map is nil or an alist of keys, the parent is
     inspected for :map argument and the keys are merged
     recursively from parent to parent till a symbol :map slot is
     met. If :map is a symbol, it must be a keymap, in which case
     this keymap is used and no parents are further inspected
     for :map slot. If :map is an alist it must be suitable for
     `easy-mmode-define-keymap'.")
   (init-functions
    :initarg :init-functions
    :initform '()
    :type list
    :documentation
    "List of functions to run at the initialization time.
     All init-functions in the inheritance chain are called. Parents
     hooks first. So, if current config object C inherits from object
     B, which in turn inherits from object A. Then A's init-functions
     are called first, then B's and then C's.
     Either customize this slot or use `object-add-to-list' function.")
   
   (-hostmode
    :type (or null pm-chunkmode)
    :documentation
    "Dynamically populated `pm-chunkmode' object.")
   (-innermodes
    :type list
    :initform '()
    :documentation
    "Dynamically populated list of chunkmodes objects that
    inherit from `pm-hbtchunkmode'.")
   (-buffers
    :initform '()
    :type list
    :documentation
    "Holds all buffers associated with current buffer. Dynamically populated.")
   (-hist
    :initform '()
    :type list
    :documentation "Internal. Used to store various user history
    values. Use `pm--get-hist' and `pm--put-hist' to place key
    value pairs into this list."))
  
  "Configuration for a polymode. Each polymode buffer contains a local
variable `pm/polymode' instantiated from this class or a subclass
of this class.")

(defclass pm-polymode-one (pm-polymode)
  ((innermode
    :initarg :innermode
    :type symbol
    :custom symbol
    :documentation
    "Symbol of the chunkmode. At run time this object is cloned
     and placed in -innermodes slot."))
  
  "Configuration for a simple polymode that allows only one
innermode. For example noweb.")

(defclass pm-polymode-multi (pm-polymode)
  ((innermodes
    :initarg :innermodes
    :type list
    :custom list
    :initform nil
    :documentation
    "List of names of the chunkmode objects that are associated
     with this configuration. At initialization time, all of
     these are cloned and plased in -innermodes slot."))
  
  "Configuration for a polymode that allows multiple (known in
advance) innermodes.")

(defclass pm-polymode-multi-auto (pm-polymode-multi)
  ((auto-innermode
    :initarg :auto-innermode
    :type symbol
    :custom symbol
    :documentation
    "Name of pm-hbtchunkmode-auto object (a symbol). At run time
     this object is cloned and placed in -auto-innermodes with
     coresponding :mode slot initialized at run time.")
   (-auto-innermodes
    :type list
    :initform '()
    :documentation
    "List of chunkmode objects that are auto-generated in
    `pm-get-span' method for this class."))
  
  "Configuration for a polymode that allows multiple innermodes
that are not known in advance. Examples are org-mode and markdown.")



;;; CHUNKMODE CLASSES
(defclass pm-chunkmode (pm-root)
  ((mode :initarg :mode
    :type symbol
    :initform nil
    :custom symbol)
   (protect-indent-line :initarg :protect-indent-line
    :type boolean
    :initform t
    :custom boolean
    :documentation
    "Whether to modify local `indent-line-function' by narrowing
    to current span first")
   (indent-offset :initarg :indent-offset
    :type integer
    :initform 0
    :documentation
    "Offset to add when indenting chunk's line. Takes efeect only
    when :protect-indent-line is non-nil.")
   (font-lock-narrow :initarg :font-lock-narrow
    :type boolean
    :initform t
    :documentation
    "Whether to narrow to span during font lock")
   (adjust-face :initarg :adjust-face
    :type (or number face list)
    :custom (or number face list)
    :initform nil
    :documentation
    "Fontification adjustments chunk face. It should be either,
    nil, number, face or a list of text properties as in
    `put-text-property' specification. If nil no highlighting
    occurs. If a face, use that face. If a number, it is a
    percentage by which to lighten/darken the default chunk
    background. If positive - lighten the background on dark
    themes and darken on light thems. If negative - darken in
    dark thems and lighten in light thems.")
   
   (-buffer
    :type (or null buffer)
    :initform nil))
  
  "Representatioin of the chunkmode object.")

(defclass pm-bchunkmode (pm-chunkmode)
  ()
  "Representation of the hostmode objects. Basemodes are the
  main (parent) modes in the buffer. For example for a the
  web-mdoe the hostmode is `html-mode', for nowweb mode the host
  mode is usually `latex-mode', etc.")

(defclass pm-hbtchunkmode (pm-chunkmode)
  ((head-mode
    :initarg :head-mode
    :type symbol
    :initform 'fundamental-mode
    :custom symbol
    :documentation
    "Chunks' header mode. If set to 'body, the head is considered
    part of the chunk body. If set to 'host, head is considered
    part of the including host mode.")
   (tail-mode
    :initarg :tail-mode
    :type symbol
    :initform nil
    :custom symbol
    :documentation
    "If nil, it is the same as :HEAD-MODE. Otherwise, the same
    rules as for the :head-mode apply.")
   (head-reg
    :initarg :head-reg
    :initform ""
    :type (or string symbol)
    :custom (or string symbol)
    :documentation "Regexp for the chunk start (aka head)")
   (tail-reg
    :initarg :tail-reg
    :initform ""
    :type (or string symbol)
    :custom (or string symbol)
    :documentation "Regexp for chunk end (aka tail)")
   (adjust-face
    :initform 2)
   (head-adjust-face
    :initarg :head-adjust-face
    :initform font-lock-type-face
    :type (or null number face list)
    :custom (or null number face list)
    :documentation
    "Can be a number, list or face.")
   (tail-adjust-face
    :initarg :tail-adjust-face
    :initform nil
    :type (or null number face list)
    :custom (or null number face list)
    :documentation
    "Can be a number, list or face. If nil, take the
    configuration from :head-adjust-face.")
   
   (-head-buffer
    :type (or null buffer)
    :initform nil
    :documentation
    "This buffer is set automatically to -buffer if :head-mode is
    'body, and to base-buffer if :head-mode is 'host")
   (-tail-buffer
    :initform nil
    :type (or null buffer)))
  
  "Representation of an inner chunkmode.")

(defclass pm-hbtchunkmode-auto (pm-hbtchunkmode)
  ((retriever-regexp :initarg :retriever-regexp
    :type (or null string)
    :custom string
    :initform nil
    :documentation
    "Regexp that is used to retrive the modes symbol from the
    head of the chunkmode chunk. fixme: elaborate")
   (retriever-num :initarg :retriever-num
    :type integer
    :custom integer
    :initform 1
    :documentation
    "Subexpression to be matched by :retriver-regexp")
   (retriever-function :initarg :retriever-function
    :type symbol
    :custom symbol
    :initform nil
    :documentation
    "Function symbol used to retrive the modes symbol from the
    head of the chunkmode chunk. It is called with no arguments
    with the point positioned at the beginning of the chunk
    header. It must return the mode name string or symbol (need
    not include '-mode' postfix).)"))

  "Representation of an inner chunkmode")

(provide 'polymode-classes)
