/// <summary>
    /// Attempts to remove the item from the server, if the ticket doesn't exist on the servers side due to it timing out and such then
    /// it will not be removed.
    /// </summary>
    /// <returns><c>true</c>, if item from server was removed, <c>false</c> otherwise.</returns>
    /// <param name="ticket">Ticket.</param>
    public bool RemoveItemFromServer(ItemTicket ticket)
    {
        // Ensure the ticket is both valid to prevent wasting the servers time
        if (ticket && ticket.IsValid() && ticket == m_itemRequestResponse)
        {
            if (Network.isServer)
            {
                PropagateRemovalAtIndex(ticket);
            }

            else
            {
                networkView.RPC("PropagateRemovalAtIndex", RPCMode.Server, ticket.uniqueID, ticket.itemID, ticket.itemIndex);
            }

            // Reset the response to maintain security of the inventory
            ResetResponse(false);

            // Transaction completed successfully
            return(true);
        }


        // If this point has been reached then a problem has occurred
        Debug.LogError(name + ": NetworkInventory.RemoveItemFromServer() transaction failed.");
        ResetResponse(false);
        return(false);
    }
    /// <summary>
    /// Attempts to add an item to the inventory, note if you haven't been given express permission from your latest request this will fail.
    /// Also it's worth noting that the return value doesn't mean the server will definitely add the item, if any error occurs it will not exist.
    /// </summary>
    /// <returns><c>true</c>, if the transaction goes through, <c>false</c> otherwise.</returns>
    /// <param name="ticket">The ticket given by the server which authorises your transaction.</param>
    public bool AddItemToServer(ItemTicket ticket)
    {
        // Check the item exists and whether the transaction has been authorised
        if (ticket && ticket.IsValid() && ticket == m_itemAddResponse)
        {
            // Unity silliness again
            if (Network.isServer)
            {
                ServerAddItem(ticket);
            }

            else
            {
                networkView.RPC("ServerAddItem", RPCMode.Server, ticket.uniqueID, ticket.itemID, ticket.itemIndex);
            }

            // Reset the response to ensure the security of future transactions
            ResetResponse(false);

            // Transaction processed successfully
            return(true);
        }


        // If this point has been reached then a problem has occurred
        Debug.LogError(name + ".NetworkInventory.AddItemToServer() transaction failed.");
        ResetResponse(false);
        return(false);
    }
    // Used to ensure the validity of a ticket just before handing it in
    public void RequestTicketValidityCheck(ItemTicket ticket)
    {
        if (ticket && ticket.IsValid())
        {
            // Reset the response, don't call the function otherwise it will break AddItemToServer() and RemoveItemFromServer()
            m_hasServerResponded     = false;
            m_ticketValidityResponse = false;

            // All that needs to be done is just contact the server to find out if the ticket still exists in the list
            if (Network.isServer)
            {
                TicketValidityCheck(ticket, m_blankMessage);
            }

            else
            {
                networkView.RPC("TicketValidityCheck", RPCMode.Server, ticket.uniqueID, ticket.itemID, ticket.itemIndex);
            }
        }

        else
        {
            ResetResponse(true);
        }
    }
    // Used to perform a synchronised removal
    void PropagateRemovalAtIndex(ItemTicket ticket)
    {
        //Debug.Log(ticket.ToString());
        if (ticket.IsValid())
        {
            // The correct index is guaranteed for the clients so only determine it for the server
            int index = Network.isServer ? DetermineTicketIndex(ticket) : ticket.itemIndex;
            //Debug.Log("Index: " + index);
            // Check if it is valid
            if (IsValidIndex(index))
            {
                // Remove or null the item based on the passed parameter
                if (m_nullRemovedItems)
                {
                    m_inventory[index]       = null;
                    m_isItemRequested[index] = false;
                }

                else
                {
                    //Debug.Log("Removing at: " + index);
                    m_inventory.RemoveAt(index);
                    m_isItemRequested.RemoveAt(index);

                    // Reset the ticket so the expiration coroutine knows it has been removed
                    m_requestTickets.RemoveAt(index);
                }

                // Propagate the change to the clients
                if (Network.isServer)
                {
                    // Give clients the correct index
                    ticket.itemIndex = index;

                    // Propagate the removal
                    Debug.Log("Sending removal notification to others.");
                    networkView.RPC("PropagateRemovalAtIndex", RPCMode.Others, ticket.uniqueID, ticket.itemID, ticket.itemIndex);
                }
            }

            else
            {
                Debug.LogError("Attempt to remove an item from " + name + " with an invalid or expired ticket.");
            }
        }
    }
    void ServerAddItem(ItemTicket ticket)
    {
        if (ticket.IsValid())
        {
            // Attempt to find the first null value, if a position hasn't been specified
            if (m_nullRemovedItems && !IsValidIndex(ticket.itemIndex))
            {
                ticket.itemIndex = FindFirstNull();
            }

            // Finally propagate the addition
            PropagateItemAtIndex(ticket.itemIndex, ticket.itemID);
        }

        else
        {
            Debug.LogError("Attempt to add item with invalid or expired ticket in " + name + ".NetworkInventory");
        }
    }
    // An ItemTicket version is provided to increase performance as items time out.
    void RequestCancel(ItemTicket ticket)
    {
        if (ticket.IsValid())
        {
            // If the index is invalid we know that the ticket is an add request
            if (!IsValidIndex(ticket.itemIndex))
            {
                --addRequests;
            }

            else
            {
                // The index of the cancellation
                int index = DetermineTicketIndex(ticket);

                // Attempt to cancel the ticket
                if (IsValidIndex(index))
                {
                    // Reset the ticket

                    m_requestTickets[index].Reset();
                    m_isItemRequested[index] = false;

                    // Check to see if the desired index was a null item, this means that it was an add requests
                    if (!m_inventory[index])
                    {
                        --addRequests;
                    }
                }

                else
                {
                    Debug.LogError("An attempt was made to cancel a request which doesn't exist in " + name + ".NetworkInventory.");
                }
            }
        }

        else
        {
            Debug.LogError("Attempt to cancel invalid ticket in " + name + ".NetworkInventory");
        }
    }
    // Causes the server to cancel a request so that others can request the item
    public void RequestServerCancel(ItemTicket ticket)
    {
        Debug.Log("Cancelling ticket: " + ticket);
        // Ensure we are not wasting time by checking if the ticket is valid
        if (ticket && ticket.IsValid())
        {
            if (Network.isServer)
            {
                RequestCancel(ticket);
            }

            else
            {
                networkView.RPC("RequestCancel", RPCMode.Server, ticket.uniqueID, ticket.itemID, ticket.itemIndex);
            }
        }

        // Reset the response since we know they've received it
        ResetResponse(false);
    }
    // This function should be called using Invoke() after the desired period of time
    IEnumerator ExpireItemTicket(ItemTicket toExpire, float timeToWait)
    {
        //Debug.Log("Waiting to expire ticket: " + toExpire + " in " + timeToWait);

        // Wait for the desired amount of time
        yield return(new WaitForSeconds(timeToWait));

        // Tickets which have been redeemed will be reset to the standard ticket
        if (toExpire.IsValid())
        {
            // Only the server needs to manage whether the item is flagged as requested or not
            if (Network.isServer)
            {
                // Obtain the index
                int index = DetermineTicketIndex(toExpire);

                // Flag the item as unrequested
                if (IsValidIndex(index))
                {
                    // Reset the request
                    m_isItemRequested[index] = false;
                }

                // Must be an add request
                else
                {
                    --addRequests;
                }
            }

            // Reset the ticket to ensure it's invalid
            toExpire.Reset();

            Debug.Log("Expiring ItemTicket: " + toExpire.uniqueID + " / " + toExpire.itemID + " / " + toExpire.itemIndex);
        }
    }