<commit_before><?php

/**
 * Node is the abstract class that governs all node objects, like process, datastore
 * etc. For all storage access methods, they could currently go in the Element
 * class, but this would reduce flexibility should the approach to loading
 * a DFD be changed (for instance so that Node objects could be loaded
 * independently of the DFD)
 *
 * @author <NAME>
 * @author <NAME>
 */
abstract class Node extends Element
{
    //<editor-fold desc="Attributes" defaultstate="collapsed">
    /**
     * This is a container which holds the UUIDs of eevry link coming out from 
     * this node
     * @var ID[]
     */
    protected $linkList;

    //</editor-fold>
    
    //<editor-fold desc="Constructor" defaultstate="collapsed">
    /**
     * This is the constructor for the Node Class.  It takes in 2 parameters; 
     * the first is always a valid storage medium, the second one is either an 
     * id or an associative array.  If the second parameter is an id of a valid 
     * node subclass the node is loaded in from the storage medium.  If the 
     * second parameter was an id of anything else it is passed to the 
     * constructor for Element for it to handle.  If the second parameter is an 
     * associative array it is likewise passed to the Element constructor for it
     *  to handle.  
     * @param {ReadStorable,WriteStorable} $datastore
     * @param ID $id    the UUID of either the parent Diagram or the id of the 
     *                      Node to be loaded (can be replaced by an assocative array
     *                      to load
     * @param Mixed[] $assocativeArray
     */
    public function __construct()
    {
        //check number of paramenters
        if(func_num_args() == 2)
        {
            //check type of second parameter
            if (is_a(func_get_arg(1), "ID"))
            {
                //if second parameter is an id of a node subclass object
                $type = func_get_arg(0)->getTypeFromUUID(func_get_arg(1));
                if (is_subclass_of($type, "Node"))
                {
                    $this->id = func_get_arg(1);
                    // Storage is set here, as entity (parent) is never called
                    $this->storage = func_get_arg(0);
                    if (!is_subclass_of($this->storage, "ReadStorable"))
                    {
                        throw new BadConstructorCallException("Passed storage object does not implement ReadStorable.");
                    }
                    if (!is_subclass_of($this->storage, "WriteStorable"))
                    {
                        throw new BadConstructorCallException("Passed storage object does not implement WriteStorable.");
                    }
                    $assocativeArray = $this->storage->loadNode(func_get_arg(1));
                    $this->loadAssociativeArray($assocativeArray);
                }
                //second parameter was an id of a diagram object so call the higher constructor and add this object to the nodeList of that Diagram
                else if (is_subclass_of($type, 'Diagram'))
                {
                    //call the parent constructor and set the linkList to be an empty list
                    parent::__construct(func_get_arg(0), func_get_arg(1));
                    $this->linkList = array();
                    $this->save();
                    //add this node to the parent diagram's node list
                    //$theDiagram = new $type($this->storage, func_get_arg(1));
                    //$theDiagram->addNode($this);
                    //$theDiagram->update();
                }
                //the second parameter did not decend from a Node or a Diagram object
                else
                {
                    throw new BadConstructorCallException("The id passed to the Node Constructor was neither a valid Node or Diagram decended object");
                }
            }
            //second parameter should be an associative array so pass it along to Element's constructor
            else
            {
                parent::__construct(func_get_arg(0), func_get_arg(1));
                $this->save();
            }
        }
        else
        {
            throw new BadConstructorCallException("An incorrect number of parameters were passed to the Node constructor");
        }
    }

    //</editor-fold>
    
    //<editor-fold desc="Accessor functions" defaultstate="collapsed">
    //<editor-fold desc="Link functions" defaultstate="collapsed">

    /**
     * This is a function that gets the number of links that connect to this node
     * @return int the number of links 
     */
    public function getNumberOfLinks()
    {
        return count($this->linkList);
    }

    /**
     * Function that returns the links that connect to this node
     * @return string[] an array of all the uuid of the links to this node
     */
    public function getLinks()
    {
        return $this->linkList;
    }

    /**
     * Function that adds a new link to the list of links
     * Should ONLY be called by a object descended from Link, otherwise may
     * break DFD
     * 
     * @param DataFlow $newLink
     * @throws BadFunctionCallException
     */
    public function addLink($newLink)
    {
        //ensure that this is only called by a Link object
        $trace=debug_backtrace();
        $caller=array_shift($trace);
        $caller=array_shift($trace);
        if($caller['class'] != 'Link')
        {
            throw new BadFunctionCallException("addLink() was not called by a Link object");
        }
        
        // Check that it is a link
        if (is_subclass_of($newLink, "Link"))
        {
            //create an new associative array and add it to the list
            $link['id']  = $newLink->getId();
            $link['label'] = $newLink->getLabel();
            array_push($this->linkList, $link);
            $this->update();
        }
        else<commit_msg>Summary - Added user integration to Node and cleaned up constuctor<commit_after><?php

/**
 * Node is the abstract class that governs all node objects, like process, datastore
 * etc. For all storage access methods, they could currently go in the Element
 * class, but this would reduce flexibility should the approach to loading
 * a DFD be changed (for instance so that Node objects could be loaded
 * independently of the DFD)
 *
 * @author <NAME>
 * @author <NAME>
 */
abstract class Node extends Element
{
    //<editor-fold desc="Attributes" defaultstate="collapsed">
    /**
     * This is a container which holds the UUIDs of eevry link coming out from 
     * this node
     * @var ID[]
     */
    protected $linkList;

    //</editor-fold>
    
    //<editor-fold desc="Constructor" defaultstate="collapsed">
    /**
     * This is the constructor for the Node Class.  It takes in 3 parameters; 
     * the first is always a valid storage medium, the second one is a user 
     * The third is an id or an associative array.  If the third parameter is an id of a valid 
     * node subclass the node is loaded in from the storage medium.  If the 
     * third parameter was an id of anything else it is passed to the 
     * constructor for Element for it to handle.  If the third parameter is an 
     * associative array it is likewise passed to the Element constructor for it
     *  to handle.  
     * @param ReadStorable,WriteStorable $storage
     * @param User $user
     * @param ID $id    the UUID of either the parent Diagram or the id of the 
     *                      Node to be loaded (can be replaced by an assocative array
     *                      to load
     * @param Mixed[] $assocativeArray
     */
    public function __construct()
    {
        //check number of paramenters
        if(func_num_args() == 3)
        {
            // Check type of tird parameter
            if (is_a(func_get_arg(2), "ID"))
            {
                // If third parameter is an id of a node subclass object
                $type = func_get_arg(0)->getTypeFromUUID(func_get_arg(1));
                if (is_subclass_of($type, "Node"))
                {
                    $this->ConstructNodeByID(func_get_arg(0), func_get_arg(1), func_get_arg(2));
                }
                // Third parameter was an id of a diagram object so call the higher constructor and add this object to the nodeList of that Diagram
                else if (is_subclass_of($type, 'Diagram'))
                {
                    $this->ConstructLinkWithDiagram(func_get_arg(0), func_get_arg(1), func_get_arg(2));
                }
                // Third parameter did not Descend from a Node or a Diagram object
                else
                {
                    throw new BadConstructorCallException("The id passed to the Node Constructor was neither a valid Node or Diagram decended object");
                }
            }
            // Third parameter should be an associative array so pass it along to Element's constructor
            else
            {
                $this->ConstructLinkFromAssocArray(func_get_arg(0), func_get_arg(1), func_get_arg(2))
            }
        }
        else
        {
            throw new BadConstructorCallException("An incorrect number of parameters were passed to the Node constructor");
        }
    }
    
    /**
     * "Constructs" Node by loading from an ID
     * Node($storage, $user, $id)
     * @param Readable,Writable $storage
     * @param User $user
     * @param ID $id
     * @throws BadConstructorCallException
     */
    protected function ConstructNodeByID($storage, $user, $id)
    {
        // Storage is set here, as entity (parent) is never called
        $this->setStorage($storage);
        
        $assocativeArray = $this->storage->loadNode($storage);
        
        // Authorization step
        if($this->verifyThenSetUser($user, $assocativeArray['originator']))
        {
            $this->loadAssociativeArray($assocativeArray);
        }
        else
        {
            // TODO: Should throw an authorization exception
            throw new BadConstructorCallException("The user is not authorized to add access this object.");
        } 
        // Save the ID after authorization has occurred
        $this->id = $id;
        $this->save();
    }
    
    /**
     * "Constructs" new Node and attaches it to a diagram
     * Node($storage, $user, $id)
     * @param type $storage
     * @param type $user
     * @param type $id
     */
    protected function ConstructLinkWithDiagram($storage, $user, $id)
    {
        // Call the parent constructor and set the linkList to be an empty list
        // Authorization handled by parent (Element) constructor
        parent::__construct(func_get_arg(0), func_get_arg(1));
        $this->linkList = array();
        $this->save();
    }
    
    /**
     * "Constructs" a Node from an associative array supplied by the client.
     * If client has attempted to set links here, it throws an error, as clients
     * are not supposed to do that.
     * Node($storage, $user, $associativeArray)
     * @param Readable,Writable $storage
     * @param User $user
     * @param Mixed[] $associativeArray
     */
    protected function ConstructLinkFromAssocArray($storage, $user, $associativeArray)
    {
        // Client shouldn't be trying to PUT links, block any such attempts
        if (isset($associativeArray['linkList']))
        {
            throw new BadConstructorCallException("Node does not support PUT operations with links.")
        }
        // Authorization handled by parent (Element) constructor
        parent::__construct(func_get_arg(0), func_get_arg(1), func_get_arg(2));
        $this->save();
    }

    //</editor-fold>
    
    //<editor-fold desc="Accessor functions" defaultstate="collapsed">
    //<editor-fold desc="Link functions" defaultstate="collapsed">

    /**
     * This is a function that gets the number of links that connect to this node
     * @return int the number of links 
     */
    public function getNumberOfLinks()
    {
        return count($this->linkList);
    }

    /**
     * Function that returns the links that connect to this node
     * @return string[] an array of all the uuid of the links to this node
     */
    public function getLinks()
    {
        return $this->linkList;
    }

    /**
     * Function that adds a new link to the list of links
     * Should ONLY be called by a object descended from Link, otherwise may
     * break DFD
     * 
     * @param DataFlow $newLink
     * @throws BadFunctionCallException
     */
    public function addLink($newLink)
    {
        //ensure that this is only called by a Link object
        $trace=debug_backtrace();
        $caller=array_shift($trace);
        $caller=array_shift($trace);
        if($caller['class'] != 'Link')
        {
            throw new BadFunctionCallException("addLink() was not called by a Link object");
        }
        
        // Check that it is a link
        if (is_subclass_of($newLink, "Link"))
        {
            // Check that the users match before committing the operation
            if (!$this->verifyUser($user, $newLink->user->getId()))
            {
                // TODO: Authorization error
                throw new BadFunctionCallException("User does not have access to a required object for this operation.");
            }
            //create an new associative array and add it to the list
            $link['id']  = $newLink->getId();
            $link['label'] = $newLink->getLabel();
            array_push($this->linkList, $link);
            $this->update();
        }
        else
{'fraction_non_alphanumeric': 0.08881915048897972, 'fraction_numerical': 0.0023354254853306085, 'mean_word_length': 1.9673018622780425, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1519174', 'n_tokens_mistral': 3584, 'n_tokens_neox': 3471, 'n_words': 1317}