/// <summary>
        /// Render a batch of RenderSettings
        /// </summary>
        public async Task <RenderBatchResponse> RenderBatch(RenderBatchRequest req)
        {
            if (Client == null)
            {
                throw new InvalidOperationException("Client not connected");
            }
            if (CurrentTask != null)
            {
                throw new InvalidOperationException("Already rendering");
            }

            RenderBatchResponse resp = null;

            _taskCancelToken = new CancellationTokenSource();
            try
            {
                CurrentTask = req.TaskID;

                UpdateActivity("Render Loading..");

                resp = await Client.Send <RenderBatchResponse>(req, _taskCancelToken.Token);
            }
            finally
            {
                UpdateActivity("");
                CurrentTask      = null;
                _taskCancelToken = null;
            }
            return(resp);
        }
        /// <summary>
        /// Async executes a batch of subtasks on node
        /// </summary>
        private async Task <SubTaskBatchResult> ExecuteSubTasksAsync(RenderNode node, Action <RenderSubTask, RenderBatchResult> onResult, params RenderSubTask[] tasks)
        {
            List <RenderRequest> reqs = tasks.Select(x => x.GetRenderRequest()).ToList();

            List <RenderBatchResult> results = new List <RenderBatchResult>();
            Action <RenderNode, RenderBatchResult> onAnyResult = (bnode, result) =>
            {
                RenderSubTask task = tasks.FirstOrDefault(x => x.ID == result.TaskID);
                if (task != null)
                {
                    lock (results)
                        results.Add(result);
                    onResult(task, result);
                }
            };

            Stopwatch time = new Stopwatch();

            time.Start();
            try
            {
                node.OnBatchResult += onAnyResult;


                RenderBatchRequest req = RenderSubTask.GetRenderBatchRequest(ID, tasks);
                req.Settings.ForEach(x => x.RenderType = node.RenderType);
                RenderBatchResponse resp = await node.RenderBatch(req);

                if (resp == null)
                {
                    return(new SubTaskBatchResult(new Exception("Render fail: (null)")));
                }

                if (resp.Success == false)
                {
                    return(new SubTaskBatchResult(new Exception("Render fail: " + resp.Message)));
                }

                if (req.Settings.Count > 0)
                {
                    decimal pixelsRendered = req.Settings.Sum(x => (x.Height * (x.Y2 - x.Y)) * (x.Width * (x.X2 - x.X)));
                    node.UpdatePerformance((int)pixelsRendered, (int)time.ElapsedMilliseconds);
                }
            }
            finally
            {
                node.OnBatchResult -= onAnyResult;
                time.Stop();
            }
            return(new SubTaskBatchResult(results.ToArray()));
        }
        public RenderBatchResponse Packet_RenderBatch(RenderBatchRequest req)
        {
            if (!_blender.IsVersionAvailable(req.Version))
            {
                return new RenderBatchResponse()
                       {
                           TaskID  = req.TaskID,
                           Success = false,
                           Message = "Version not prepared.."
                       }
            }
            ;

            try
            {
                //Validate Settings
                string filePath = SessionData.GetFilePath(req.SessionID);

                if (filePath == null)
                {
                    return new RenderBatchResponse()
                           {
                               TaskID  = req.TaskID,
                               Success = false,
                               Message = "Blend file was not available"
                           }
                }
                ;

                for (int i = 0; i < req.Settings.Count; i++)
                {
                    Shared.RenderPacketModel settings = req.Settings[i];

                    if (settings == null)
                    {
                        settings = new Shared.RenderPacketModel();
                    }
                    if (settings.Cores <= 0)
                    {
                        settings.Cores = Environment.ProcessorCount;
                    }

                    settings.Cores = Math.Min(Environment.ProcessorCount, settings.Cores);
                }

                BlenderRenderSettings[] batch = req.Settings.Select(x => BlenderRenderSettings.FromRenderSettings(x)).ToArray();

                DateTime lastUpdate = DateTime.Now;

                List <string> exceptions = new List <string>();

                //Render
                List <string> files = _blender.RenderBatch(req.Version, filePath, batch,
                                                           (process) =>
                {
                    process.OnBlenderStatus += (status) =>
                    {
                        if (DateTime.Now.Subtract(lastUpdate).TotalMilliseconds > UPDATE_TIMING_MS)
                        {
                            lastUpdate = DateTime.Now;
                            SendPacket(new RenderInfoResponse()
                            {
                                TaskID        = req.TaskID,
                                TilesFinished = status.TilesFinish,
                                TilesTotal    = status.TilesTotal,
                                Time          = status.Time,
                                TimeRemaining = status.TimeRemaining
                            });
                        }
                    };
                    process.OnBlenderCompleteTask += (taskID) =>
                    {
                        BlenderRenderSettings settings = batch.FirstOrDefault(x => x.TaskID == taskID);
                        if (settings != null)
                        {
                            SendPacket(new RenderBatchResult()
                            {
                                Data    = File.ReadAllBytes(settings.Output),
                                Success = true,
                                TaskID  = settings.TaskID
                            });
                        }
                    };
                    process.OnBlenderException += (excp) => exceptions.Add(excp);
                });

                //Handle Result
                if (files == null || files.Count != req.Settings.Count)
                {
                    if (exceptions.Count == 0)
                    {
                        return new RenderBatchResponse()
                               {
                                   TaskID  = req.TaskID,
                                   Success = false,
                                   Message = "Missing Files?"
                               }
                    }
                    ;
                    else
                    {
                        return new RenderBatchResponse()
                               {
                                   TaskID  = req.TaskID,
                                   Success = false,
                                   Message = string.Join(", ", exceptions)
                               }
                    };
                }
                else
                {
                    //Cleanup
                    //string data = Convert.ToBase64String(File.ReadAllBytes(file));
                    foreach (string file in files)
                    {
                        File.Delete(file);
                    }
                    if (exceptions.Count > 0)
                    {
                        return(new RenderBatchResponse()
                        {
                            Success = false,
                            TaskID = req.TaskID,
                            SubTaskIDs = req.Settings.Select(X => X.TaskID).ToList(),
                            Message = string.Join(", ", exceptions)
                        });
                    }
                    else
                    {
                        return(new RenderBatchResponse()
                        {
                            Success = true,
                            TaskID = req.TaskID,
                            SubTaskIDs = req.Settings.Select(X => X.TaskID).ToList()
                        });
                    }
                };
            }
            catch (Exception ex)
            {
                return(new RenderBatchResponse()
                {
                    TaskID = req.TaskID,
                    Success = false,
                    Message = "Exception:" + ex.Message
                });
            }
        }