private Task<IJobTemplate> CreateJobTemplate(string templateName, JobTemplateType templateType, params ITaskTemplate[] taskTemplates)
        {
            X509Certificate2 certToUse = null;
            DataServiceContext dataContext = this._cloudMediaContext.DataContextFactory.CreateDataServiceContext();
            JobTemplateData jobTemplateData = new JobTemplateData { Name = templateName, TemplateType = (int)templateType };

            jobTemplateData.InitCloudMediaContext(this._cloudMediaContext);

            dataContext.AddObject(JobTemplateBaseCollection.JobTemplateSet, jobTemplateData);

            foreach (ITaskTemplate taskTemplate in taskTemplates)
            {
                Verify(taskTemplate);

                dataContext.AddRelatedObject(jobTemplateData, TaskTemplatesPropertyName, taskTemplate);

                if (taskTemplate.Options.HasFlag(TaskOptions.ProtectedConfiguration) && string.IsNullOrWhiteSpace(this.Id))
                {
                    ProtectTaskConfiguration((TaskTemplateData)taskTemplate, ref certToUse, dataContext);
                }
            }

            AssetNamingSchemeResolver<AssetData, OutputAsset> assetIdMap = new AssetNamingSchemeResolver<AssetData, OutputAsset>();

            jobTemplateData.JobTemplateBody = CreateJobTemplateBody(assetIdMap, taskTemplates);

            jobTemplateData.NumberofInputAssets = string.IsNullOrWhiteSpace(this.Id)
                ? assetIdMap.Inputs.Count
                : ((IJob)this).InputMediaAssets.Count;

            return dataContext
                .SaveChangesAsync(SaveChangesOptions.Batch, jobTemplateData)
                .ContinueWith<IJobTemplate>(
                    t =>
                    {
                        t.ThrowIfFaulted();

                        JobTemplateData data = (JobTemplateData)t.AsyncState;
                        IJobTemplate jobTemplateToReturn = this._cloudMediaContext.JobTemplates.Where(c => c.Id == data.Id).First();

                        return jobTemplateToReturn;
                    });
        }
        private static string CreateJobTemplateBody(AssetNamingSchemeResolver<AssetData, OutputAsset> assetMap, ITaskTemplate[] taskTemplates)
        {
            using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            {
                XmlWriterSettings outputSettings =
                    new XmlWriterSettings
                    {
                        Encoding = Encoding.UTF8,
                        Indent = true
                    };

                XmlWriter jobTemplateBodyWriter = XmlWriter.Create(stringWriter, outputSettings);
                jobTemplateBodyWriter.WriteStartDocument();

                jobTemplateBodyWriter.WriteStartElement("jobTemplate");

                foreach (ITaskTemplate taskTemplate in taskTemplates)
                {
                    TaskTemplateData taskTemplateData = (TaskTemplateData)taskTemplate;
                    taskTemplateData.NumberofInputAssets = taskTemplateData.TaskInputs.Length;
                    taskTemplateData.NumberofOutputAssets = taskTemplateData.TaskOutputs.Length;

                    string taskTemplateId = string.Empty;
                    string taskTemplateBody = string.Empty;

                    if (!string.IsNullOrWhiteSpace(taskTemplateData.TaskTemplateBody))
                    {
                        // The task template was created using an already submitted job.
                        StringReader stringReader = null;
                        try
                        {
                            stringReader = new StringReader(taskTemplateData.TaskTemplateBody);
                            using (XmlReader taskTemplateBodyReader = XmlReader.Create(stringReader))
                            {
                                stringReader = null;
                                taskTemplateBodyReader.ReadToNextSibling(TaskBodyNodeName);

                                taskTemplateId = taskTemplateBodyReader.GetAttribute(TaskTemplateIdAttributeName);
                                taskTemplateBody = taskTemplateBodyReader.ReadInnerXml();
                            }
                        }
                        finally
                        {
                            if (stringReader != null)
                            {
                                stringReader.Dispose();
                            }
                        }
                    }

                    taskTemplateData.Id = !string.IsNullOrWhiteSpace(taskTemplateId)
                        ? taskTemplateId
                        : string.Concat("nb:ttid:UUID:", Guid.NewGuid());

                    jobTemplateBodyWriter.WriteStartElement(TaskBodyNodeName);
                    jobTemplateBodyWriter.WriteAttributeString(TaskTemplateIdAttributeName, taskTemplateData.Id);

                    if (!string.IsNullOrWhiteSpace(taskTemplateBody))
                    {
                        // The task template was created using an already submitted job.
                        jobTemplateBodyWriter.WriteRaw(taskTemplateBody);
                    }
                    else
                    {
                        foreach (IAsset input in taskTemplateData.TaskInputs)
                        {
                            jobTemplateBodyWriter.WriteStartElement(InputAssetNodeName);
                            jobTemplateBodyWriter.WriteString(assetMap.GetAssetId(input));
                            jobTemplateBodyWriter.WriteEndElement();
                        }

                        foreach (IAsset output in taskTemplateData.TaskOutputs)
                        {
                            jobTemplateBodyWriter.WriteStartElement(OutputAssetNodeName);

                            int options = (int)output.Options;
                            jobTemplateBodyWriter.WriteAttributeString(AssetCreationOptionsAttributeName, options.ToString(CultureInfo.InvariantCulture));

                            jobTemplateBodyWriter.WriteString(assetMap.GetAssetId(output));
                            jobTemplateBodyWriter.WriteEndElement();
                        }
                    }

                    jobTemplateBodyWriter.WriteEndElement();
                }

                jobTemplateBodyWriter.WriteEndDocument();
                jobTemplateBodyWriter.Flush();

                return stringWriter.ToString();
            }
        }
        private void InnerSubmit(DataServiceContext dataContext)
        {
            if (!string.IsNullOrWhiteSpace(this.TemplateId))
            {
                dataContext.AddObject(JobBaseCollection.JobSet, this);

                foreach (IAsset asset in this.InputMediaAssets)
                {
                    AssetData target = asset as AssetData;
                    if (target == null)
                    {
                        throw new ArgumentException(StringTable.ErrorInputTypeNotSupported);
                    }

                    dataContext.AttachTo(AssetCollection.AssetSet, asset);
                    dataContext.AddLink(this, InputMediaAssetsPropertyName, target);
                }
            }
            else
            {
                X509Certificate2 certToUse = null;
                Verify(this);

                dataContext.AddObject(JobBaseCollection.JobSet, this);

                List<AssetData> inputAssets = new List<AssetData>();
                AssetNamingSchemeResolver<AssetData, OutputAsset> assetNamingSchemeResolver = new AssetNamingSchemeResolver<AssetData, OutputAsset>(inputAssets);

                foreach (ITask task in ((IJob)this).Tasks)
                {
                    Verify(task);
                    TaskData taskData = (TaskData)task;

                    if (task.Options.HasFlag(TaskOptions.ProtectedConfiguration))
                    {
                        ProtectTaskConfiguration(taskData, ref certToUse, dataContext);
                    }

                    taskData.TaskBody = CreateTaskBody(assetNamingSchemeResolver, task.InputAssets.ToArray(), task.OutputAssets.ToArray());
                    taskData.InputMediaAssets.AddRange(task.InputAssets.OfType<AssetData>().ToArray());
                    taskData.OutputMediaAssets.AddRange(
                        task.OutputAssets
                            .OfType<OutputAsset>()
                            .Select(
                                c =>
                                {
                                    AssetData assetData = new AssetData { Name = c.Name, Options = (int)c.Options, AlternateId = c.AlternateId };
                                    assetData.InitCloudMediaContext(this._cloudMediaContext);

                                    return assetData;
                                })
                            .ToArray());
                    dataContext.AddRelatedObject(this, TasksPropertyName, taskData);
                }

                foreach (IAsset asset in inputAssets)
                {
                    dataContext.AttachTo(AssetCollection.AssetSet, asset);
                    dataContext.AddLink(this, InputMediaAssetsPropertyName, asset);
                }
            }
        }
        private static string CreateTaskBody(AssetNamingSchemeResolver<AssetData, OutputAsset> assetNamingSchemeResolver, IEnumerable<IAsset> inputs, IEnumerable<IAsset> outputs)
        {
            using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            {
                XmlWriterSettings outputSettings = new XmlWriterSettings();
                outputSettings.Encoding = Encoding.UTF8;
                outputSettings.Indent = true;
                XmlWriter taskBody = XmlWriter.Create(stringWriter, outputSettings);
                taskBody.WriteStartDocument();
                taskBody.WriteStartElement(TaskBodyNodeName);

                foreach (IAsset input in inputs)
                {
                    taskBody.WriteStartElement(InputAssetNodeName);
                    taskBody.WriteString(assetNamingSchemeResolver.GetAssetId(input));
                    taskBody.WriteEndElement();
                }

                foreach (IAsset output in outputs)
                {
                    taskBody.WriteStartElement(OutputAssetNodeName);

                    var outputAsset = (OutputAsset)output;
                    int options = (int)outputAsset.Options;
                    taskBody.WriteAttributeString(AssetCreationOptionsAttributeName, options.ToString(CultureInfo.InvariantCulture));
                    if (!string.IsNullOrEmpty(outputAsset.Name))// Ignore empty string for the name
                    {
                        taskBody.WriteAttributeString(OutputAssetNameAttributeName, outputAsset.Name);

                    }
                    taskBody.WriteString(assetNamingSchemeResolver.GetAssetId(output));
                    taskBody.WriteEndElement();
                }

                taskBody.WriteEndDocument();
                taskBody.Flush();

                return stringWriter.ToString();
            }
        }