/// <summary>
        /// Get a specific tracking from your account. If the trackingGet.id property
        /// is defined it will get that tracking from the system, if not it will take
        /// the tracking tracking.number and the tracking.slug for identify the tracking
        /// </summary>
        /// <param name="trackingGet">A Tracking to get.</param></param>
        /// <returns> A Tracking object with the response</returns>

        public Tracking getTrackingByNumber(Tracking trackingGet)
        {
            String parametersExtra;

            if (trackingGet.id != null && !trackingGet.id.Equals(""))
            {
                parametersExtra = trackingGet.id;
            }
            else
            {
                //get the require fields if any (postal_code, tracking_account etc..)
                String paramRequiredFields = replaceFirst(trackingGet.getQueryRequiredFields(), "&", "?");
                parametersExtra = trackingGet.slug + "/" + trackingGet.trackingNumber +
                                  paramRequiredFields;
            }
            JObject  response     = request("GET", "/trackings/" + parametersExtra, null);
            JObject  trackingJSON = (JObject)response["data"]["tracking"];
            Tracking tracking     = null;

            if (trackingJSON.Count != 0)
            {
                tracking = new Tracking(trackingJSON);
            }

            return(tracking);
        }
        /// <summary>
        /// Return the tracking information of the last checkpoint of a single tracking
        /// </summary>
        /// <param name="tracking"> A Tracking to get the last checkpoint of, it should have tracking number and slug at least</param>
        /// <returns>The last Checkpoint object</returns>
        public Checkpoint getLastCheckpoint(Tracking tracking)
        {
            String parametersExtra = "";

            if (tracking.id != null && !(tracking.id.Equals("")))
            {
                parametersExtra = tracking.id;
            }
            else
            {
                String paramRequiredFields = this.replaceFirst(tracking.getQueryRequiredFields(), "&", "?");
                parametersExtra = tracking.slug + "/" + tracking.trackingNumber + paramRequiredFields;
            }

            JObject response = this.request("GET", "/last_checkpoint/" + parametersExtra, null);

            JObject    checkpointJSON = (JObject)response["data"]["checkpoint"];
            Checkpoint checkpoint     = null;

            if (checkpointJSON.Count != 0)
            {
                checkpoint = new Checkpoint(checkpointJSON);
            }

            return(checkpoint);
        }
        /// <summary>
        ///  Get a specific tracking from your account. If the trackingGet.id property
        /// is defined it will get that tracking from the system, if not it will take
        /// the tracking tracking.number and the tracking.slug for identify the tracking
        /// </summary>
        /// <param name="trackingGet">A Tracking to get</param>
        /// <param name="fields">A list of fields wanted to be in the response</param>
        /// <param name="lang">A String with the language desired. Support Chinese to
        /// English translation for china-ems and china-post only</param>
        /// <returns></returns>
        public Tracking getTrackingByNumber(Tracking trackingGet, List <FieldTracking> fields, String lang)
        {
            String parametersAll;

            //encode the fields required
            String      params_query;
            QueryString qs = new QueryString();

            if (fields != null)
            {
                qs.add("fields", parseListFieldTracking(fields));
            }

            if (lang != null && !lang.Equals(""))
            {
                qs.add("lang", lang);
            }

            params_query = replaceFirst(qs.ToString(), "&", "?");

            if (trackingGet.id != null && !trackingGet.id.Equals(""))
            {
                parametersAll = trackingGet.id + params_query;
            }
            else
            {
                //get the require fields if any (postal_code, tracking_account etc..)
                String paramRequiredFields = trackingGet.getQueryRequiredFields();
                parametersAll = trackingGet.slug +
                                "/" + trackingGet.trackingNumber + params_query + paramRequiredFields;
            }

            JObject  response     = this.request("GET", "/trackings/" + parametersAll, null);
            JObject  trackingJSON = (JObject)response["data"]["tracking"];
            Tracking tracking     = null;

            if (trackingJSON.Count != 0)
            {
                tracking = new Tracking(trackingJSON);
            }

            return(tracking);
        }
        /// <summary>
        /// Updates a tracking of your account
        /// </summary>
        /// <param name="tracking">  A Tracking object with the information to update
        ///                The fields trackingNumber and slug SHOULD be informed, otherwise an exception will be thrown
        ///               The fields an user can update are: smses, emails, title, customerName, orderID, orderIDPath,
        ///               customFields</param>
        /// <returns>The last Checkpoint object</returns>
        public Tracking putTracking(Tracking tracking)
        {
            String parametersExtra = "";

            if (tracking.id != null && !(tracking.id.CompareTo("") == 0))
            {
                parametersExtra = tracking.id;
            }
            else
            {
                String paramRequiredFields = this.replaceFirst(tracking.getQueryRequiredFields(), "&", "?");
                parametersExtra = tracking.slug + "/" + tracking.trackingNumber + paramRequiredFields;
            }


            JObject response = this.request("PUT", "/trackings/" + parametersExtra, tracking.generatePutJSON());

            return(new Tracking((JObject)response["data"]["tracking"]));
        }
        /// <summary>
        /// Return the tracking information of the last checkpoint of a single tracking
        /// </summary>
        /// <param name="tracking"> A Tracking to get the last checkpoint of, it should have tracking number and slug at least.</param>
        /// <param name="fields"> A list of fields of checkpoint wanted to be in the response</param>
        /// <param name="lang"> A String with the language desired. Support Chinese to English translation
        ///                      for china-ems and china-post only</param>
        /// <returns>The last Checkpoint object</returns>

        public Checkpoint getLastCheckpoint(Tracking tracking, List <FieldCheckpoint> fields, String lang)
        {
            String      parameters = null;
            QueryString qs         = new QueryString();

            if (fields != null)
            {
                qs.add("fields", string.Join(",", fields));
            }
            if (lang != null && !lang.Equals(""))
            {
                qs.add("lang", lang);
            }
            parameters = this.replaceFirst(qs.ToString(), "&", "?");

            String parametersExtra = "";

            if (tracking.id != null && !tracking.id.Equals(""))
            {
                parametersExtra = tracking.id + parameters;
            }
            else
            {
                String paramRequiredFields = tracking.getQueryRequiredFields();
                parametersExtra = tracking.slug + "/" + tracking.trackingNumber + parameters + paramRequiredFields;
            }

            JObject response = this.request("GET", "/last_checkpoint/" + parametersExtra, null);

            JObject    checkpointJSON = (JObject)response["data"]["checkpoint"];
            Checkpoint checkpoint     = null;

            if (checkpointJSON.Count != 0)
            {
                checkpoint = new Checkpoint(checkpointJSON);
            }

            return(checkpoint);
        }
        /// <summary>
        /// Mark a tracking as completed. The tracking won't auto update until retrack it.
        /// </summary>
        /// <param name="tracking"></param>
        /// <param name="reason"> One of DELIVERED, LOST or RETURNED_TO_SENDER.
        /// Mark the tracking as completed with DELIVERED. The tag of the tracking will be updated to Delivered and the subtag will be updated to Delivered_001.
        /// Mark the tracking as completed with LOST. The tag of the tracking will be updated to Exception and the subtag will be updated to Exception_013.
        /// Mark the tracking as completed with RETURNED_TO_SENDER. The tag of the tracking will be updated to Exception and the subtag will be updated to Exception_011.
        /// </param>
        /// <returns></returns>
        public Tracking markTrackingAsCompeleted(Tracking tracking, string reason)
        {
            JObject body = new JObject();
            String  parametersExtra;

            //get the require fields if any (postal_code, tracking_account etc..)
            String paramRequiredFields = replaceFirst(tracking.getQueryRequiredFields(), "&", "?");

            parametersExtra = tracking.slug + "/" + tracking.trackingNumber + "/mark-as-completed" +
                              paramRequiredFields;
            body.Add("reason", reason);

            JObject  response     = request("POST", "/trackings/" + parametersExtra, body.ToString());
            JObject  trackingJSON = (JObject)response["data"]["tracking"];
            Tracking trackingObj  = null;

            if (trackingJSON.Count != 0)
            {
                trackingObj = new Tracking(trackingJSON);
            }

            return(trackingObj);
        }
        /// <summary>
        /// Retrack an expired tracking once
        /// </summary>
        /// <param name="tracking"> tracking A Tracking to reactivate, it should have tracking number and slug at least.</param>
        /// <param name="fields"> A list of fields of checkpoint wanted to be in the response</param>
        /// <param name="lang"> A String with the language desired. Support Chinese to English translation
        ///                      for china-ems and china-post only</param>
        /// <returns> A JSONObject with the response. It will contain the status code of the operation, trackingNumber,
        ///         slug and active (to true)</returns>

        public bool retrack(Tracking tracking)
        {
            String paramRequiredFields = this.replaceFirst(tracking.getQueryRequiredFields(), "&", "?");

            JObject response = this.request("POST", "/trackings/" + tracking.slug +
                                            "/" + tracking.trackingNumber + "/retrack" + paramRequiredFields, null);

            if ((int)response["meta"]["code"] == 200)
            {
                if ((bool)response["data"]["tracking"]["active"])
                {
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }
        }