/// <summary>
        /// Fetches data for the "Visits" block. Calling this method will
        /// result on two calls (it not already cached) to the Analytics API.
        /// The first call will fetch data for the previous period, while the
        /// second call will fetch data for the current period.
        /// </summary>
        public static VisitsBlock GetBlock(DataQuery query) {

            // Declare the data options
            AnalyticsDataOptions options = new AnalyticsDataOptions {
                Metrics = new[] {
                    AnalyticsMetric.Visits,
                    AnalyticsMetric.Pageviews,
                    AnalyticsMetric.NewVisits,
                    AnalyticsMetric.AvgTimeOnSite
                },
                Sorting = new AnalyticsSortOptions().AddDescending(AnalyticsMetric.Visits)
            };

            switch (query.Type) {
                case DataQueryType.Page:
                    throw new NotImplementedException();
                    //options.Filters = query.CreateFilterOptionsFromPageUrls();
                    break;
            }

            // Fetch the data
            AnalyticsDataResponse data1;
            AnalyticsDataResponse data2;
            query.GetCachedDataPreviousAndCurrent("Visits", out data1, out data2, options);

            // Get the first row of each dataset
            var row1 = data1.Rows.FirstOrDefault();
            var row2 = data2.Rows.FirstOrDefault();

            return new VisitsBlock {
                HasData = (row1 != null && row1.GetInt32(AnalyticsMetric.Pageviews) > 0) || (row2 != null && row2.GetInt32(AnalyticsMetric.Pageviews) > 0),
                Items = new[] {
                    query.FormatVisitDataInt32(AnalyticsMetric.Visits, row1, row2),
                    query.FormatVisitDataInt32(AnalyticsMetric.Pageviews, row1, row2),
                    query.FormatVisitDataInt32(AnalyticsMetric.NewVisits, row1, row2),
                    query.FormatVisitDataDouble(AnalyticsMetric.AvgTimeOnSite, row1, row2)
                }
            };

        }
 public AnalyticsDataResponse GetData(string profileId, AnalyticsDataOptions options) {
     return AnalyticsDataResponse.ParseJson(Raw.GetData(profileId, options));
 }
 public AnalyticsDataResponse GetData(AnalyticsProfile profile, AnalyticsDataOptions options) {
     return AnalyticsDataResponse.ParseJson(Raw.GetData(profile.Id, options));
 }
        public static DevicesBlock GetBlock(DataQuery query) {

            // Declare the data options
            var options = new AnalyticsDataOptions {
                StartDate = query.CurrentStartDate,
                EndDate = query.CurrentEndDate,
                Metrics = AnalyticsMetric.Visits + AnalyticsMetric.Pageviews,
                Dimensions = AnalyticsDimension.DeviceCategory
            };

            switch (query.Type) {
                case DataQueryType.Page:
                    throw new NotImplementedException();
                    //options.Filters = query.CreateFilterOptionsFromPageUrls();
                    break;
            }

            // Fetch the data
            AnalyticsDataResponse data;
            try {

                data = query.GetCachedData("Devices", options);

            } catch (Exception ex) {

                throw new DashboardException(ex.Message + " (Unable to fetch date for period from " + query.PreviousStartDate.ToString("yyyy-MM-dd") + " to " + query.PreviousEndDate.ToString("yyyy-MM-dd") + " for block \"Devices\")");

            }

            // Filter out any rows where the the "ga:visits" value is either "NaN" or "0"
            AnalyticsDataRow[] rows = data.Rows.Where(x => x.GetString(AnalyticsMetric.Visits) != "NaN" && x.GetString(AnalyticsMetric.Visits) != "0").ToArray();

            // Calculate the total visits and pageviews
            int totalVisits = 0;
            int totalPageviews = 0;
            foreach (AnalyticsDataRow row in rows) {
                totalVisits += row.GetInt32(AnalyticsMetric.Visits);
                totalPageviews += row.GetInt32(AnalyticsMetric.Pageviews);
            }
            
            if (data.Rows.Length == 0) {
                return new DevicesBlock {
                    HasData = false,
                    Items = new object[0]
                };
            }

            List<object> items = new List<object>();

            // Iterate through the rows
            foreach (AnalyticsDataRow row in rows) {

                int visits = row.GetInt32(AnalyticsMetric.Visits);
                int pageviews = row.GetInt32(AnalyticsMetric.Pageviews);

                double visitsPercent = visits / (double) totalVisits * 100;
                double pageviewsPercent = pageviews / (double) totalPageviews * 100;

                string category = row.GetString(AnalyticsDimension.DeviceCategory);

                items.Add(new {
                    category = category,
                    text = query.Context.Translate("device_" + category),
                    visits = new {
                        raw = visits,
                        text = query.Context.Format(visits),
                        percent = new {
                            raw = visitsPercent,
                            text = query.Context.Format(visitsPercent) + "%"
                        }
                    },
                    pageviews = new {
                        raw = pageviews,
                        text = DashboardContext.Current.Format(pageviews),
                        percent = new {
                            raw = pageviewsPercent,
                            text = query.Context.Format(pageviewsPercent) + "%"
                        }
                    }
                });

            }
           
            return new DevicesBlock {
                HasData = items.Count > 0,
                Items = items.ToArray()
            };

        }
        ///// <summary>
        ///// Returns an array with exactly two elements. The first element will be data for the
        ///// previous preiod (as defined by properties <code>PreviousStartDate</code> and
        ///// <code>PreviousEndDate</code>). The second element will be data for the current period
        ///// (as defined by <code>CurrentStartDate</code> and <code>CurrentEndDate</code>).
        ///// </summary>
        ///// <param name="key"></param>
        ///// <param name="options"></param>
        internal void GetCachedDataPreviousAndCurrent(string key, out AnalyticsDataResponse previous, out AnalyticsDataResponse current, AnalyticsDataOptions options) {

            previous = GetCachedData(key + "_Previous", new AnalyticsDataOptions {
                StartDate = PreviousStartDate,
                EndDate = PreviousEndDate,
                Metrics = options.Metrics,
                Dimensions = options.Dimensions,
                Filters = options.Filters,
                Sorting = options.Sorting,
                MaxResults = options.MaxResults
            });

            current = GetCachedData(key + "_Current", new AnalyticsDataOptions {
                StartDate = CurrentStartDate,
                EndDate = CurrentEndDate,
                Metrics = options.Metrics,
                Dimensions = options.Dimensions,
                Filters = options.Filters,
                Sorting = options.Sorting,
                MaxResults = options.MaxResults
            });

        }
        internal AnalyticsDataResponse GetCachedData(string key, AnalyticsDataOptions options) {

            // Declare the path to the cache directory
            string cacheDir = HttpContext.Current.Server.MapPath("~/App_Data/Skybrud.Dashboard/AnalyticsCache/" + (PageId > 0 ? "Pages/" : ""));

            // Generate a combined key
            string combinedKey = (PageId > 0 ? PageId + "" : Site.Analytics.ProfileId) + "_" + key + "_" + Days + ".json";

            // Declare the path to the cache file (based on the cache key)
            string path = Path.Combine(cacheDir, combinedKey + ".json");

            // Return the cache response if present and not expired
            if (EnableCaching && File.Exists(path) && File.GetLastWriteTimeUtc(path) > DateTime.Today) {
                return AnalyticsDataResponse.LoadJson(path);
            }

            // Get the data from the Analytics API
            AnalyticsDataResponse response = Service.Analytics.GetData(Site.Analytics.ProfileId, options);

            // Save the response to the cache
            response.SaveJson(path);

            // Return the response
            return response;

        }
        public static LineChartBlock GetBlock(DataQuery query) {

            // Declare the data options
            AnalyticsDataOptions options = new AnalyticsDataOptions {
                StartDate = query.CurrentStartDate,
                EndDate = query.CurrentEndDate,
                Metrics = AnalyticsMetric.Visits + AnalyticsMetric.Pageviews
            };

            if (query.Days <= 1) {
                options.Dimensions = AnalyticsDimension.Hour;
            } else if (query.Days <= 31) {
                options.Dimensions = AnalyticsDimension.Date;
                //options.Sorting = new AnalyticsSortOptions().AddAscending(AnalyticsDimension.Date);
            } else {
                options.Dimensions = AnalyticsDimension.YearWeek;
            }

            // Add any extra options?
            switch (query.Type) {
                case DataQueryType.Page:
                    throw new NotImplementedException();
                    //options.Filters = query.CreateFilterOptionsFromPageUrls();
                    break;
            }

            // Fetch the data
            AnalyticsDataResponse data;
            try {
                data = query.GetCachedData("LineChart", options);
            } catch (Exception ex) {
                throw new DashboardException(ex.Message + " (Unable to fetch data for period from " + query.PreviousStartDate.ToString("yyyy-MM-dd") + " to " + query.PreviousEndDate.ToString("yyyy-MM-dd") + " for block \"LineChart\")");
            }

            object ddata;

            if (data.Rows.Length == 0) {
                ddata = new {
                    columns = new object[0],
                    rows = new object[0]
                };
            } else {

                object[] columns = new object[data.ColumnHeaders.Length];
                object[] rows = new object[data.Rows.Length];

                for (int i = 0; i < data.ColumnHeaders.Length; i++) {
                    var column = data.ColumnHeaders[i];
                    columns[i] = new {
                        alias = column.Name.Substring(3),
                        label = query.Context.Translate(column.Name)
                    };
                }

                for (int i = 0; i < data.Rows.Length; i++) {

                    AnalyticsDataRow row = data.Rows[i];

                    object[] rowdata = new object[row.Cells.Length];

                    for (int j = 0; j < row.Cells.Length; j++) {
                        rowdata[j] = GetCellData(row.Cells[j], query);
                    }

                    rows[i] = rowdata;

                }
                
                ddata = new { columns, rows };
            
            }

            var datasets = new object[] {
                new {
                    label = DashboardContext.Current.Translate(AnalyticsMetric.Pageviews),
                    fillColor = "#35353d",
                    strokeColor = "#35353d"
                },
                new  {
                    label = DashboardContext.Current.Translate(AnalyticsMetric.Visits),
                    fillColor = "red",//"rgba(141, 146, 157, 1)",
                    strokeColor = "red"//"rgba(141, 146, 157, 1)"
                }
            };

            object[] items = (
                from row in data.Rows
                let first = row.Cells[0]
                select (object) new {
                    label = query.FormatCell(first),
                    visits = query.FormatInt32(AnalyticsMetric.Visits, row),
                    pageviews = query.FormatInt32(AnalyticsMetric.Pageviews, row)
                }
            ).ToArray();

            return new LineChartBlock {
                HasData = data.Rows.Any(x => x.GetInt32(AnalyticsMetric.Visits) > 0),
                Data = ddata,
                Datasets = datasets,
                Items = items.ToArray(),
                Debug = new {
                    query = data.Query.ToJson(),
                    days = query.Days
                }
            };

        }
        public string GetData(string profileId, AnalyticsDataOptions options) {

            // Validate arguments
            if (options == null) throw new ArgumentNullException("options");

            // Generate the name value collection
            NameValueCollection query = options.ToNameValueCollection(profileId, Client.AccessToken);

            // Make the call to the API
            return SocialUtils.DoHttpGetRequestAndGetBodyAsString("https://www.googleapis.com/analytics/v3/data/ga", query);

        }
 public string GetData(AnalyticsProfile profile, AnalyticsDataOptions options) {
     return GetData(profile.Id, options);
 }