#!/usr/bin/env python
from bridges.sl_element import *

##
#
# 	@author Mihai Mehedint, Kalpathi Subramanian
#
#
# 	@brief This class is used to create doubly linked element objects.
#
#	This class extends Element and takes a generic parameter <E> representing
#	application specific data. This element forms the basic building block for
#	doubly linked lists. Doubly linked elements have two links,
# 	"next" and "previous", that point to the previous and succeeding nodes along the list.
#
#	Elements contain a visualizer (ElementVisualizer) object for setting visual
#	attributes (color, shape, opacity, size), necessary for displaying them in a web
#	browser.
#
#	Elements also have a LinkVisualizer object that is used when they are linked to
#	another element, appropriate for setting link attributes, such as in linked lists,
#	between the current element and its next or previous nodes.
#
#   @author Matthew Mcquaigue
#   @date  2018, 6/24/19
#
#   \sa Doubly Linked List tutorial : http://bridgesuncc.github.io/tutorials/DoublyLinkedList.html
#

#
class DLelement(SLelement):

    def __init__(self, *args, **kwargs) -> None:
        """
        Constructor for DLelement
        Kwargs:
            (object) e: the genereic application specific object that DLelement is holding
            next: the DLelement that should be assigned to the next pointer
            prev: the DLelement that should be assigned to the prev pointer
            (str) label: the label for this DLelement
        Return:
            None
        """
        super(DLelement, self).__init__(**kwargs)
        self._next = kwargs.get('next')
        self._prev = kwargs.get('prev')

    def get_data_structure_type(self) -> str:
        """
        This method gets the data structure type
        Returns:
            str: representing the data structure type
        """
        return "DoublyLinkedList"

    @property
    def next(self):
        """
        Getter for the next element in Dlelement
        Returns:
            element pointed to by this element
        """
        return self._next

    @next.setter
    def next(self, el):
        """
        Setter for the next element
        Args:
            el: element to be set 
        Returns:
            None
        """
        self._next = el

    @property
    def prev(self):
        """
        Getter for the prev element in Dlelement
        Returns:
            element that is prior to this element
        """
        return self._prev

    @prev.setter
    def prev(self, el):
        """
        Setter for the prev element
        Args:
            el: element to be set

        Returns:
            None
        """
        #remove any existing link visualizer from this node
        if self._prev is not None:
            self.remove_link_visualizer(self._prev)
        self._prev = el
        #  add a new link visualizer
        if el is not None:
            self.set_link_visualizer(el)

    def get_data_structure_representation(self) -> dict:
        """
        Getter for the json representation of this list
        Returns:
            dict: representing the JSON format
        """
        #  map to reorder the nodes for building JSON
        node_map = dict()
        #  get teh list nodes
        nodes = []
        SLelement.get_list_elements(self, nodes)
        #  generate the JSON of the list nodes
        nodes_JSON = []
        k = 0
        while k < len(nodes):
            node_map[nodes[k]] = k
            nodes_JSON.append(nodes[k].get_element_representation())
            k += 1
        links_JSON = []
        k = 0
        while k < len(nodes):
            par = nodes[k]
            nxt = par.next
            prv = par.prev
            if nxt is not None:
                #  add the link
                links_JSON.append(self.get_link_representation(par.get_link_visualizer(nxt), str(node_map.get(par)), str(node_map.get(nxt))))
            if prv is not None:
                #  add the link
                links_JSON.append(self.get_link_representation(par.get_link_visualizer(prv), str(node_map.get(par)), str(node_map.get(prv))))
            k += 1
        #  add the link
        json_dict = {
            "nodes": nodes_JSON,
            "links": links_JSON
        }
        return json_dict
