<commit_before>﻿using System;
using System.Net;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using Jil;
using StackExchange.Adzerk.Models;
using System.Net.Http;

namespace StackExchange.Adzerk
{
    public interface IClient
    {
        string CreateReport(IReport report);
        ReportResult PollForResult(string id);
        ReportResult RunReport(IReport report);

        IEnumerable<AdType> ListAdTypes();
        IEnumerable<Advertiser> ListAdvertisers();
        IEnumerable<Campaign> ListCampaigns();
        IEnumerable<Channel> ListChannels();
        IEnumerable<Creative> ListAdvertiserCreatives(long advertiserId);
        IEnumerable<Flight> ListFlights();
        IEnumerable<Flight> ListCampaignFlights(long campaignId);
        IEnumerable<Login> ListLogins();
        IEnumerable<Priority> ListPriorities();
        IEnumerable<Publisher> ListPublishers();
        IEnumerable<Site> ListSites();
        IEnumerable<Zone> ListZones();

        Campaign GetCampaign(long campaignId);
        Campaign UpdateCampaign(Campaign campaign);

        Flight GetFlight(long flightId);
        Flight UpdateFlight(Flight flight);
    }

    public class Client : IClient
    {
        public const int CURRENT_VERSION = 1;
        public const int POLL_DELAY = 1000;
        public const int LIST_PAGE_SIZE = 1000;

        private readonly string _apiKey;
        private readonly HttpClient _client;

        public Client(string apiKey, HttpClientHandler customHandler = null)
        {
            this._apiKey = apiKey;
            
            if(customHandler != null)
            {
                _client = new HttpClient(customHandler);
            }
            else
            {
                _client = new HttpClient();
            }
        }

        private string ApiRoute(string path, int? page)
        {
            if (page.HasValue)
                return $"http://api.adzerk.net/v{CURRENT_VERSION}/{path}?page={page}&pageSize={LIST_PAGE_SIZE}";
            else
                return $"http://api.adzerk.net/v{CURRENT_VERSION}/{path}";
        }

        private HttpResponseMessage ExecuteApiRequest(string route, int? page = null, HttpMethod method = null, string bodyKey = null, string bodyValue = null)
        {
            if (method == null)
            {
                method = HttpMethod.Get;
            }

            var request = new HttpRequestMessage(method, ApiRoute(route, page));

            request.Headers.Add("X-Adzerk-ApiKey", _apiKey);

            if (bodyKey != null)
            {
                request.Content = new FormUrlEncodedContent(new[] {
                    new KeyValuePair<string, string>(bodyKey, bodyValue)
                });
            }

            var response = _client.SendAsync(request).Result;

            if (response.StatusCode != HttpStatusCode.OK)
            {
                var message = $"Adzerk API error ({response.StatusCode}): {response.Content.ReadAsStringAsync().Result}";
                throw new AdzerkApiException(message, new {request, response});
            }

            return response;
        }

        public string CreateReport(IReport report)
        {
            var response = ExecuteApiRequest("report/queue", null, HttpMethod.Post, "criteria", ReportSerializer.SerializeReport(report));

            try
            {
                var result = JSON.DeserializeDynamic(response.Content.ReadAsStringAsync().Result);
                return result.Id;
            }
            catch (Exception)
            {
                throw new AdzerkApiException("Report result does not contain report Id.", new {response.RequestMessage, response});
            }
        }

        public class ReportResultWrapper
        {
            public int Status;
            public string Message;
            public ReportResult Result;
        }

        private ReportResultWrapper pollForResult(string id)
        {
            var response = ExecuteApiRequest("report/queue/" + id);

            return JSON.Deserialize<ReportResultWrapper>(response.Content.ReadAsStringAsync().Result);
        }

        public ReportResult PollForResult(string id)
        {
            var res = pollForResult(id);

            if (res.Status == 1)
            {
                return null;
            }

            if (res.Status == 2)
            {
                return res.Result;
            }

            var message = $"Adzerk API error: {res.Message}";
            throw new AdzerkApiException(message, new {response = res});
        }

        public ReportResult RunReport(IReport report)
        {
            var id = CreateReport(report);

            var res = pollForResult(id);

            while (res.Status == 1)
            {
                Task.Delay(POLL_DELAY);

                res = pollForResult(id);
            }

            if (res.Status == 2)
            {
                return res.Result;
            }

            var message = $"Adzerk API error: {res.Message}";
            throw new AdzerkApiException(message, new {response = res});
        }

        private IEnumerable<T> List<T>(string resource)
        {
            int totalPages = 1;
            IEnumerable<T>[] totalItems;

            // Retrieve first page of information and setup for later stages.
            {
                var response = ExecuteApiRequest(resource, page: 1);

                try
                {
                    var result = JSON.Deserialize<ResultWrapper<T>>(response.Content.ReadAsStringAsync().Result);

                    totalPages = result.totalPages;
                    totalItems = new IEnumerable<T>[totalPages];
                    totalItems[0] = result.items;
                }
                catch (Exception ex)
                {
                    var message = $"Adzerk client error deserializing \"{resource}\" at page 0";
                    throw new AdzerkApiException(message, ex, new { response.RequestMessage, response });
                }
            }

            // Retrieve second and later pages of information.
            {
                for (var i = 1; i < totalPages; i++)
                {
                    var currentResponse = ExecuteApiRequest(resource, page: i + 1);

                    try
                    {
                        var currentResult = JSON.Deserialize<ResultWrapper<T>>(currentResponse.Content.ReadAsStringAsync().Result);
                        totalItems[i] = currentResult.items;
<commit_msg>Assume 0 pages rather than 1 in list pagination<commit_after>﻿using System;
using System.Net;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using Jil;
using StackExchange.Adzerk.Models;
using System.Net.Http;

namespace StackExchange.Adzerk
{
    public interface IClient
    {
        string CreateReport(IReport report);
        ReportResult PollForResult(string id);
        ReportResult RunReport(IReport report);

        IEnumerable<AdType> ListAdTypes();
        IEnumerable<Advertiser> ListAdvertisers();
        IEnumerable<Campaign> ListCampaigns();
        IEnumerable<Channel> ListChannels();
        IEnumerable<Creative> ListAdvertiserCreatives(long advertiserId);
        IEnumerable<Flight> ListFlights();
        IEnumerable<Flight> ListCampaignFlights(long campaignId);
        IEnumerable<Login> ListLogins();
        IEnumerable<Priority> ListPriorities();
        IEnumerable<Publisher> ListPublishers();
        IEnumerable<Site> ListSites();
        IEnumerable<Zone> ListZones();

        Campaign GetCampaign(long campaignId);
        Campaign UpdateCampaign(Campaign campaign);

        Flight GetFlight(long flightId);
        Flight UpdateFlight(Flight flight);
    }

    public class Client : IClient
    {
        public const int CURRENT_VERSION = 1;
        public const int POLL_DELAY = 1000;
        public const int LIST_PAGE_SIZE = 1000;

        private readonly string _apiKey;
        private readonly HttpClient _client;

        public Client(string apiKey, HttpClientHandler customHandler = null)
        {
            this._apiKey = apiKey;
            
            if(customHandler != null)
            {
                _client = new HttpClient(customHandler);
            }
            else
            {
                _client = new HttpClient();
            }
        }

        private string ApiRoute(string path, int? page)
        {
            if (page.HasValue)
                return $"http://api.adzerk.net/v{CURRENT_VERSION}/{path}?page={page}&pageSize={LIST_PAGE_SIZE}";
            else
                return $"http://api.adzerk.net/v{CURRENT_VERSION}/{path}";
        }

        private HttpResponseMessage ExecuteApiRequest(string route, int? page = null, HttpMethod method = null, string bodyKey = null, string bodyValue = null)
        {
            if (method == null)
            {
                method = HttpMethod.Get;
            }

            var request = new HttpRequestMessage(method, ApiRoute(route, page));

            request.Headers.Add("X-Adzerk-ApiKey", _apiKey);

            if (bodyKey != null)
            {
                request.Content = new FormUrlEncodedContent(new[] {
                    new KeyValuePair<string, string>(bodyKey, bodyValue)
                });
            }

            var response = _client.SendAsync(request).Result;

            if (response.StatusCode != HttpStatusCode.OK)
            {
                var message = $"Adzerk API error ({response.StatusCode}): {response.Content.ReadAsStringAsync().Result}";
                throw new AdzerkApiException(message, new {request, response});
            }

            return response;
        }

        public string CreateReport(IReport report)
        {
            var response = ExecuteApiRequest("report/queue", null, HttpMethod.Post, "criteria", ReportSerializer.SerializeReport(report));

            try
            {
                var result = JSON.DeserializeDynamic(response.Content.ReadAsStringAsync().Result);
                return result.Id;
            }
            catch (Exception)
            {
                throw new AdzerkApiException("Report result does not contain report Id.", new {response.RequestMessage, response});
            }
        }

        public class ReportResultWrapper
        {
            public int Status;
            public string Message;
            public ReportResult Result;
        }

        private ReportResultWrapper pollForResult(string id)
        {
            var response = ExecuteApiRequest("report/queue/" + id);

            return JSON.Deserialize<ReportResultWrapper>(response.Content.ReadAsStringAsync().Result);
        }

        public ReportResult PollForResult(string id)
        {
            var res = pollForResult(id);

            if (res.Status == 1)
            {
                return null;
            }

            if (res.Status == 2)
            {
                return res.Result;
            }

            var message = $"Adzerk API error: {res.Message}";
            throw new AdzerkApiException(message, new {response = res});
        }

        public ReportResult RunReport(IReport report)
        {
            var id = CreateReport(report);

            var res = pollForResult(id);

            while (res.Status == 1)
            {
                Task.Delay(POLL_DELAY);

                res = pollForResult(id);
            }

            if (res.Status == 2)
            {
                return res.Result;
            }

            var message = $"Adzerk API error: {res.Message}";
            throw new AdzerkApiException(message, new {response = res});
        }

        private IEnumerable<T> List<T>(string resource)
        {
            int totalPages = 0;
            IEnumerable<T>[] totalItems;

            // Retrieve first page of information and setup for later stages.
            {
                var response = ExecuteApiRequest(resource, page: 1);
                string dbgText = null;

                try
                {
                    dbgText = response.Content.ReadAsStringAsync().Result;
                    var result = JSON.Deserialize<ResultWrapper<T>>(dbgText);

                    totalPages = result.totalPages;
                    totalItems = new IEnumerable<T>[totalPages];

                    if (totalPages > 0)
                        totalItems[0] = result.items;
                }
                catch (Exception ex)
                {
                    var message = $"Adzerk client error deserializing \"{resource}\" at page 0";
                    throw new AdzerkApiException(message, ex, new { response.RequestMessage, response });
                }
            }

            // Retrieve second and later pages of information.
            {
                for (var i = 1; i < totalPages; i++)
                {
                    var currentResponse = ExecuteApiRequest(resource, page: i + 1);

                    try
                    {
                        var currentResult = JSON.Deserialize<ResultWrapper<T>>(currentResponse.Content.ReadAsStringAsync().Result);
                        totalItems[i] = currentResult.items;

{'fraction_non_alphanumeric': 0.08816652839580662, 'fraction_numerical': 0.003092239233728034, 'mean_word_length': 1.6880194607743766, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4014651', 'n_tokens_mistral': 3409, 'n_tokens_neox': 3227, 'n_words': 778}