package com.newsblur.network.domain;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.newsblur.domain.Feed;
import com.newsblur.domain.SocialFeed;

public class FeedFolderResponse {
	
	@SerializedName("starred_count")
	public int starredCount;
	
	@SerializedName("feeds")
	public Map<String, Feed> feeds;
	
	@SerializedName("flat_folders")
	public Map<String, List<Long>> folders;
	
	@SerializedName("social_feeds")
	public SocialFeed[] socialFeeds;

	public FeedFolderResponse() {
	}
	
	public FeedFolderResponse(String json, Gson gson) {
		// This is a mess but I don't see a way to parse the mixed content in
		// folders w/o going to low level Gson API
		JsonParser parser = new JsonParser();
		JsonObject asJsonObject = parser.parse(json).getAsJsonObject();
		JsonArray jsonFoldersArray = (JsonArray) asJsonObject.get("folders");
		ArrayList<String> nestedFolderList = new ArrayList<String>();
		folders = new HashMap<String, List<Long>>();
		parseFeedArray(nestedFolderList, folders, null, jsonFoldersArray);
		
		JsonElement starredCountElement = asJsonObject.get("starred_count");
		if(starredCountElement != null) {
			starredCount = gson.fromJson(starredCountElement, int.class);
		}
		
		JsonObject feedsElement = (JsonObject) asJsonObject.get("feeds");
		if(feedsElement != null) {
			feeds = new HashMap<String, Feed>();
			Set<Entry<String, JsonElement>> entrySet = feedsElement.entrySet();
			Iterator<Entry<String, JsonElement>> iterator = entrySet.iterator();
			while(iterator.hasNext()) {
				Entry<String, JsonElement> feedElement = iterator.next();
				Feed feed = gson.fromJson(feedElement.getValue(), Feed.class);
				feeds.put(feedElement.getKey(), feed);
			}
		}
		
		JsonArray socialFeedsArray = (JsonArray) asJsonObject.get("social_feeds");
		if(socialFeedsArray != null) {
			List<SocialFeed> socialFeedsList = new ArrayList<SocialFeed>();
			for(int i=0;i<socialFeedsArray.size();i++) {
				JsonElement jsonElement = socialFeedsArray.get(i);
				SocialFeed socialFeed = gson.fromJson(jsonElement, SocialFeed.class);
				socialFeedsList.add(socialFeed);
			}
			socialFeeds = socialFeedsList.toArray(new SocialFeed[socialFeedsArray.size()]);
		}
	}
	
	private void parseFeed(JsonObject asJsonObject2, List<String> parentFeedNames, Map<String, List<Long>> folders) {
		Set<Entry<String, JsonElement>> entrySet = asJsonObject2.entrySet();
		Iterator<Entry<String, JsonElement>> iterator = entrySet.iterator();
		while(iterator.hasNext()) {
			Entry<String, JsonElement> next = iterator.next();
			String key = next.getKey();
			JsonArray value = (JsonArray) next.getValue();
			parseFeedArray(parentFeedNames, folders, key, value);
		}
	}

	private void parseFeedArray(List<String> nestedFolderList,
			Map<String, List<Long>> folders, String name, JsonArray arrayValue) {
		String fullFolderName = getFolderName(name, nestedFolderList);
		ArrayList<Long> feedIds = new ArrayList<Long>();
		for(int k=0;k<arrayValue.size();k++) {
			JsonElement jsonElement = arrayValue.get(k);
			if(jsonElement.isJsonPrimitive()) {
				feedIds.add(jsonElement.getAsLong());
			} else {
				List<String> nestedFolerListCopy = new ArrayList<String>(nestedFolderList);
				if(name != null) {
					nestedFolerListCopy.add(name);
				}
				parseFeed((JsonObject) jsonElement, nestedFolerListCopy, folders);
			}
		}
		folders.put(fullFolderName, feedIds);
	}

	private String getFolderName(String key, List<String> parentFeedNames) {
		StringBuilder builder = new StringBuilder();
		for(String parentFolder: parentFeedNames) {
			builder.append(parentFolder);
			builder.append(" - ");
		}
		if(key != null) {
			builder.append(key);
		}
		return builder.toString();
	}
	
}

@@ -1556,143 +1556,417 @@
 %09%0A%09%09
-JsonObject feedsElement = (JsonObject) asJsonObject.get(%22feeds%22);%0A%09%09if(feedsElement != null) %7B%0A%09%09%09feeds = new HashMap%3CString, Feed%3E(
+// Inconsistent server response here. When user has no feeds we get%0A%09%09// %09%09%22feeds%22: %5B%5D%0A%09%09// and other times we get%0A%09%09// %09%09%22feeds%22: %7B%22309667%22: %7B%0A%09%09// So support both I guess%0A%09%09JsonElement feedsElement = asJsonObject.get(%22feeds%22);%0A%09%09feeds = new HashMap%3CString, Feed%3E();%0A%09%09if(feedsElement instanceof JsonObject) %7B%0A%09%09%09JsonObject feedsObject = (JsonObject) asJsonObject.get(%22feeds%22
 );%0A
+%09%09%09if(feedsObject != null) %7B%0A%09
 %09%09%09S
@@ -2012,22 +2012,21 @@
  = feeds
-Elemen
+Objec
 t.entryS
@@ -2031,16 +2031,17 @@
 ySet();%0A
+%09
 %09%09%09Itera
@@ -2107,16 +2107,17 @@
 r();%0A%09%09%09
+%09
 while(it
@@ -2132,24 +2132,25 @@
 asNext()) %7B%0A
+%09
 %09%09%09%09Entry%3CSt
@@ -2195,24 +2195,25 @@
 tor.next();%0A
+%09
 %09%09%09%09Feed fee
@@ -2267,24 +2267,25 @@
 class);%0A%09%09%09%09
+%09
 feeds.put(fe
@@ -2314,24 +2314,105 @@
 ed);%0A%09%09%09
+%09
 %7D%0A
+%09
 %09%09%7D%0A%09%09
+%7D // else server sent back '%22feeds%22: %5B%5D' %0A%09%09%0A%09%09socialFeeds = new SocialFeed%5B0%5D;
 %0A%09%09JsonA

Fix feed parsing issue when user has no feeds