// 
// Copyright (c) 2013-2016 Carsten Sonne Larsen <cs@innolan.dk>
// 
// 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.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Ntp.Common.Process;

namespace Ntp.Analyzer.Monitor.Server
{
    public static class Billboard
    {
        public static string Jobs(IEnumerable<Job> jobs)
        {
            var builder = new StringBuilder();

            builder.Append("ID".PadRight(3));
            builder.Append("Act".PadRight(4));
            builder.Append("Job".PadRight(15));
            builder.Append("Que".PadLeft(5));
            builder.Append("Ini".PadLeft(5));
            builder.Append("Fix".PadLeft(5));
            builder.Append("Freq".PadLeft(6));
            builder.Append("Prio".PadLeft(5));
            builder.Append("Runs".PadLeft(6));
            builder.Append("   ");
            builder.Append("Description");
            builder.AppendLine();

            const int size = 3 + 4 + 15 + 5 + 5 + 5 + 6 + 5 + 6 + 3 + 25;

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            IEnumerable<Job> orderedJobs = jobs.OrderBy(j => j.Description.Priority);

            foreach (Job job in orderedJobs)
            {
                builder.Append(job.JobId.ToString("00").PadRight(3));
                builder.Append(job.Running ? " *  " : "    ");
                builder.Append(
                    string.IsNullOrWhiteSpace(job.Description.Name)
                        ? "Unnamed".PadRight(15)
                        : job.Description.Name.
                            Substring(0, job.Description.Name.Length > 15 ? 15 : job.Description.Name.Length).
                            PadRight(15)
                    );
                builder.Append((job.Queued ? "  1" : "  0").PadLeft(5));
                builder.Append((job.Schedule.InitialRun ? "  1" : "  0").PadLeft(5));
                builder.Append((job.Schedule.FixedRun ? "  1" : "  0").PadLeft(5));
                builder.Append(job.Schedule.Frequency.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append(job.Description.Priority.ToString(CultureInfo.InvariantCulture).PadLeft(5));
                builder.Append(job.RunCount.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append("   ");
                builder.Append(job.Description.JobType);
                builder.AppendLine();
            }

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            return builder.ToString();
        }

        public static string Proc(IEnumerable<Job> jobs)
        {
            var builder = new StringBuilder();

            builder.Append("ID".PadRight(4));
            builder.Append("Job".PadRight(16));
            builder.Append("Ini".PadLeft(5));
            builder.Append("Fix".PadLeft(5));
            builder.Append("Freq".PadLeft(7));
            builder.Append("Prio".PadLeft(6));
            builder.Append("Runs".PadLeft(5));
            builder.Append("   ");
            builder.Append("State".PadRight(12));
            builder.Append("Time".PadRight(15));
            builder.AppendLine();

            const int size = 4 + 16 + 5 + 5 + 7 + 6 + 5 + 3 + 12 + 15 + 2;

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            IEnumerable<Job> orderedJobs = jobs.OrderBy(j => j.JobId);

            foreach (Job job in orderedJobs)
            {
                builder.Append(job.JobId.ToString("00").PadRight(4));
                builder.Append(
                    job.Description.Name.Substring(0,
                        job.Description.Name.Length > 15 ? 15 : job.Description.Name.Length).PadRight(15));
                builder.Append((job.Schedule.InitialRun ? "  1" : "  0").PadLeft(5));
                builder.Append((job.Schedule.FixedRun ? "  1" : "  0").PadLeft(5));
                builder.Append(job.Schedule.Frequency.ToString(CultureInfo.InvariantCulture).PadLeft(7));
                builder.Append(job.Description.Priority.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append(job.RunCount.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append("   ");
                builder.Append(job.State.PadRight(12));
                builder.Append(job.TotalRuntime.PadLeft(15).Substring(0, 15));
                builder.AppendLine();
            }

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            return builder.ToString();
        }

        public static string Running(IEnumerable<Job> jobs)
        {
            var list = jobs.ToList();
            if (list.Count(j => j.Running) == 0)
            {
                return "No jobs are currently running.";
            }

            var builder = new StringBuilder();

            builder.Append("ID".PadRight(4));
            builder.Append("Job".PadRight(16));
            builder.Append("Ini".PadLeft(5));
            builder.Append("Fix".PadLeft(5));
            builder.Append("Freq".PadLeft(7));
            builder.Append("Prio".PadLeft(6));
            builder.Append("Runs".PadLeft(5));
            builder.Append("   ");
            builder.Append("State".PadRight(12));
            builder.Append("Time".PadRight(15));
            builder.AppendLine();

            const int size = 4 + 16 + 5 + 5 + 7 + 6 + 5 + 3 + 12 + 15 + 2;

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            IEnumerable<Job> orderedJobs = list.Where(j => j.Running).OrderBy(j => j.JobId);

            foreach (Job job in orderedJobs)
            {
                builder.Append(job.JobId.ToString("00").PadRight(4));
                builder.Append(
                    job.Description.Name.Substring(0,
                        job.Description.Name.Length > 15 ? 15 : job.Description.Name.Length).PadRight(15));
                builder.Append((job.Schedule.InitialRun ? "  1" : "  0").PadLeft(5));
                builder.Append((job.Schedule.FixedRun ? "  1" : "  0").PadLeft(5));
                builder.Append(job.Schedule.Frequency.ToString(CultureInfo.InvariantCulture).PadLeft(7));
                builder.Append(job.Description.Priority.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append(job.RunCount.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append("   ");
                builder.Append(job.State.PadRight(12));
                builder.Append(job.Runtime.PadLeft(15).Substring(0, 15));
                builder.AppendLine();
            }

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            return builder.ToString();
        }

        public static string Schedule(IEnumerable<ScheduledJob> jobs)
        {
            var builder = new StringBuilder();

            builder.AppendLine("Server time: " + DateTime.Now.ToLongTimeString());
            builder.AppendLine();

            builder.Append("ID".PadRight(4));
            builder.Append("Job".PadRight(15));
            builder.Append("Ini".PadLeft(4));
            builder.Append("Fix".PadLeft(5));
            builder.Append("Freq".PadLeft(6));
            builder.Append("Prio".PadLeft(5));
            builder.Append("Runs".PadLeft(6));
            builder.Append("   ");
            builder.Append("Next".PadRight(8));
            builder.AppendLine();

            const int size = 4 + 15 + 4 + 5 + 6 + 5 + 6 + 3 + 8 + 2;

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            IEnumerable<ScheduledJob> orderedJobs = jobs.OrderBy(j => j.Run);

            foreach (ScheduledJob job in orderedJobs)
            {
                builder.Append(job.Job.JobId.ToString("00").PadRight(4));
                builder.Append(
                    job.Job.Description.Name.Substring(0,
                        job.Job.Description.Name.Length > 15 ? 15 : job.Job.Description.Name.Length).PadRight(15));
                builder.Append((job.Job.Schedule.InitialRun ? "  1" : "  0").PadLeft(4));
                builder.Append((job.Job.Schedule.FixedRun ? "  1" : "  0").PadLeft(5));
                builder.Append(job.Job.Schedule.Frequency.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append(job.Job.Description.Priority.ToString(CultureInfo.InvariantCulture).PadLeft(5));
                builder.Append(job.Job.RunCount.ToString(CultureInfo.InvariantCulture).PadLeft(6));
                builder.Append("   ");
                builder.Append(job.Run.ToLongTimeString().PadLeft(8));
                builder.AppendLine();
            }

            builder.AppendLine(string.Empty.PadLeft(size, '-'));

            return builder.ToString();
        }
    }
}