//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

static void sendRemoteCommand(NetConnection *conn, S32 argc, const char **argv);

ConsoleFunctionGroupBegin( Net, "Functions for use with the network; tagged strings and remote commands.");

/*! @addtogroup Network Network
	@ingroup TorqueScriptFunctions
	@{
*/

/*! Use the commandToServer function to issue a remote procedure call the server.
    All arguments may be in tagged or non-tagged format. See 'Remote Procedure Call Samples' below
    @param func The suffix of the remote procedure name to be executed on the client.
    @param arg1 ... argn - Optional arguments to be passed to the remote procedure.
    @return No return value.
*/
ConsoleFunctionWithDocs( commandToServer, ConsoleVoid, 2, RemoteCommandEvent::MaxRemoteCommandArgs + 1, ( func, [arg1, ... , argn]? ))
{
   NetConnection *conn = NetConnection::getConnectionToServer();
   if(!conn)
      return;
   sendRemoteCommand(conn, argc - 1, argv + 1);
}

/*! Use the commandToClient function to issue a remote procedure call on a client.
    All arguments (excluding client) may be in tagged or non-tagged format. See 'Remote Procedure Call Samples' below
    @param client The numeric ID of a client gameConnection.
    @param func The suffix of the remote procedure name to be executed on the client.
    @param arg1 ... argn - Optional arguments to be passed to the remote procedure.
    @return No return value.
*/
ConsoleFunctionWithDocs( commandToClient, ConsoleVoid, 3, RemoteCommandEvent::MaxRemoteCommandArgs + 2, ( client, func, [arg1, ... , argn]? ))
{
   NetConnection *conn;
   if(!Sim::findObject(argv[1], conn))
      return;
   sendRemoteCommand(conn, argc - 2, argv + 2);
}

/*! Use the removeTaggedSTring function to remove a previously tagged string from the NetStringTable.
    @param tag A number tag ID.
    @return No return value
*/
ConsoleFunctionWithDocs(removeTaggedString, ConsoleVoid, 2, 2, ( tag ))
{
   gNetStringTable->removeString(dAtoi(argv[1]+1), true);
}

/*! Use the addTaggedString function to tag a new string and add it to the NetStringTable.
    @param string The string to tagged and placed in the NetStringTable. Tagging ignores case, so tagging the same string (excluding case differences) will be ignored as a duplicated tag.
    @return Returns a string (containing a numeric value) equivalent to the string ID for the newly tagged string
*/
ConsoleFunctionWithDocs( addTaggedString, ConsoleString, 2, 2, ( string ))
{
   NetStringHandle s(argv[1]);
   gNetStringTable->incStringRefScript(s.getIndex());

   char *ret = Con::getReturnBuffer(10);
   ret[0] = StringTagPrefixByte;
   dSprintf(ret + 1, 9, "%d", s.getIndex());
   return ret;
}

/*! Use the getTaggedString function to convert a tag to a string. This is not the same a detag() which can only be used within the context of a function that receives a tag. This function can be used any time and anywhere to convert a tag to a string.
    @param tag A numeric tag ID.
    @return Returns the string corresponding to the tag ID
*/
ConsoleFunctionWithDocs( getTaggedString, ConsoleString, 2, 2, ( tag ))
{
   const char *indexPtr = argv[1];
   if (*indexPtr == StringTagPrefixByte)
      indexPtr++;
   return gNetStringTable->lookupString(dAtoi(indexPtr));
}

/*! Use the buildTaggedString function to build a tagged string using the specified format.
    @param enable A boolean value. If set to true, network packet logging is enabled, otherwise it is disabled.
    @return No return value
*/
ConsoleFunctionWithDocs( buildTaggedString, ConsoleString, 2, 11, ( format, [arg1, ...arg9]? ))
{
   const char *indexPtr = argv[1];
   if (*indexPtr == StringTagPrefixByte)
      indexPtr++;
   const char *fmtString = gNetStringTable->lookupString(dAtoi(indexPtr));
   char *strBuffer = Con::getReturnBuffer(512);
   const char *fmtStrPtr = fmtString;
   char *strBufPtr = strBuffer;
   S32 strMaxLength = 511;
   if (!fmtString)
      goto done;

   //build the string
   while (*fmtStrPtr)
   {
      //look for an argument tag
      if (*fmtStrPtr == '%')
      {
         if (fmtStrPtr[1] >= '1' && fmtStrPtr[1] <= '9')
         {
            S32 argIndex = S32(fmtStrPtr[1] - '0') + 1;
            if (argIndex >= argc)
               goto done;
            const char *argStr = argv[argIndex];
            if (!argStr)
               goto done;
            S32 strLength = dStrlen(argStr);
            if (strLength > strMaxLength)
               goto done;
            dStrcpy(strBufPtr, argStr);
            strBufPtr += strLength;
            strMaxLength -= strLength;
            fmtStrPtr += 2;
            continue;
         }
      }

      //if we don't continue, just copy the character
      if (strMaxLength <= 0)
         goto done;
      *strBufPtr++ = *fmtStrPtr++;
      strMaxLength--;
   }

done:
   *strBufPtr = '\0';
   return strBuffer;
}

ConsoleFunctionGroupEnd( Net );

/*! @} */ // group NetworkFunctions

