/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License only.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package net.pms.dlna;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.net.URLDecoder;
import java.net.URI;
import java.net.URISyntaxException;

import net.pms.PMS;
import net.pms.util.FileUtil;
import net.pms.util.PMSUtil;
import net.pms.dlna.DLNAResource;
import net.pms.dlna.virtual.VirtualFolder;
//import net.pms.configuration.PmsConfiguration;
import net.pms.configuration.RendererConfiguration;
import net.pms.xmlwise.Plist;
import net.pms.xmlwise.XmlParseException;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jna.Platform;

public class  rz_ItunesFolder extends VirtualFolder {
	/**
	 * Returns iTunes folder. Used by manageRoot, so it is usually used as a
	 * folder at the root folder. Only works when PMS is run on MacOsX or
	 * Windows.
	 * <p>
	 * The iTunes XML is parsed fully when this method is called, so it can take
	 * some time for larger (+1000 albums) databases. TODO: Check if only music
	 * is being added.
	 * <P>
	 * This method does not support genius playlists and does not provide a
	 * media library.
	 * 
	 * @see RootFolder#getiTunesFile(boolean)
	 */
	
	private static final Logger logger = LoggerFactory.getLogger(rz_ItunesFolder.class);
	private String iTunesFileName;
	private File iTunesF;
	private RendererConfiguration rend;
	
	public rz_ItunesFolder (String name, int mode, RendererConfiguration r) {
		//---- create me
		super(name,null);
		if(name==null) {
			name="iTunes Library";
		}
		this.name=name;
		this.setDefaultRenderer(r);
		this.rend=r;
		//this.sort_enabled=true; //regzamod
		//this.rz_MetaSortType=PMS.SORT_NAME_NUM;

		try {
			iTunesFileName = getiTunesFile();
		} catch (Exception e) {
			logger.error("Something went wrong with the iTunes Library read: ", e);
		}
		if(iTunesFileName!=null) {
			iTunesF = new File(iTunesFileName);
		}
		if(mode==1) {
			//create childlen
			resolve_in();
		}
	}

	@Override
	public boolean analyzeChildren(int count) {
		//only once called when 1st open of the folder
		//analyzeChildren may process partialy, upto count.
		//so, max counts must be knowned before, i.e. by discoverChildren()
		//shoud be more refined, as for exec conditions
		
		//PMS.dbg("rz_ItunesFolder.analyzeChildren: called");
		resolve_in();
		return true;
	}
	
	@Override
	public boolean isRefreshNeeded() {
		//PMS.dbg("rz_ItunesFolder.isRefreshNeeded: called");
		long systim=System.currentTimeMillis();
		long lastim=getLastRefreshTime();
		long updtim=0;
		
		if(!resolved) return true;
		
		setLastRefreshTime(systim);
		if(lastim+2000 > systim) {
			return false;
		}
		if(iTunesF!=null) {
			updtim=iTunesF.lastModified();
		}
		if(updtim > lastim) {
			return true;
		}
		return false;
	}
	
	@Override
	public void refreshChildren() {
		//PMS.dbg("rz_ItunesFolder.refreshChildren: called");
		getChildren().clear();	// regzamod
		deleteMenus();
		resolved=false;
		resolve_in();
		setLastRefreshTime(System.currentTimeMillis());
	}
	
	public void resolve () {
		//Folder's resolve() will be called twice:
		// 1) when parent Folder opend, same as a File under the parent
		// 2) when this Folder opend, as a Folder 
		// but cann't judge which is the case. so if you attatch resolve() with Folder open action
		// --> will be twice called and cause responce slowdown 
		//PMS.dbg("rz_ItunesFolder.resolve: called --> Noop");
		//resolve_in();
	}
	
	public void resolve_in () {
		
		if(resolved) return;
		//if(this.sotype==SO_ITUNE_NOTSOLVED) return;
		resolved=true;
		
		if(PMS.rz_debug>1) {
			PMS.dbg("rz_ItunesFolder.resolve_in: Start, renderer="+rend);
		}
		
		//RendererConfiguration rend=getDefaultRenderer();
		DLNAResource res = this;
		
		if(Platform.isMac() || Platform.isWindows()) {
			Map<String, Object> iTunesLib;
			ArrayList<?> Playlists;
			HashMap<?, ?> Playlist;
			HashMap<?, ?> Tracks;
			HashMap<?, ?> track;
			ArrayList<?> PlaylistTracks;

			try {
				//String iTunesFileName = getiTunesFile();
				String name=null;

				if (iTunesF != null && iTunesF.exists()) {
					iTunesLib = Plist.load(URLDecoder.decode(iTunesFileName, System.getProperty("file.encoding"))); // loads the (nested) properties.
					Tracks = (HashMap<?, ?>) iTunesLib.get("Tracks"); // the list of tracks
					Playlists = (ArrayList<?>) iTunesLib.get("Playlists"); // the list of Playlists
					
					/*
					if(res==null) {
						res = new VirtualFolder("iTunes Library", null);
						res.setDefaultRenderer(rend); //add by regzam, need for controll_subfolder
					}
					*/

					for (Object item : Playlists) {
						Playlist = (HashMap<?, ?>) item;
						Object p=Playlist.get("Name");
						if(p!=null) {
							name=p.toString();
						}
						else {
							name="Unknown";
						}
						p=Playlist.get("Distinguished Kind");
						if(p!=null && PMS.rz_itunes_ignore_kinds!=null) {
							//-------------------------------------------------------------
							// Sample of [Distinguished Kind] in iTunes_Music_Library.xml
							// 2	Movie
							// 3	TV Shows
							// 4	Music
							// 5    AudioBooks
							// 10	Podcast
							// 22	iTunes DJ
							// 26	Genius
							// 31	iTunesU
							//-------------------------------------------------------------
							String dkind=p.toString();
							Boolean ign=false;
							for(String str : PMS.rz_itunes_ignore_kinds) {
								if(dkind.equals(str)) {
									PMS.dbg("getiTunesFolder_in: Playlist name="+name+", Distinguished Kind="+str+" --> Designated to Ignore ");
									ign=true;
									break;
								}
							}
							if(ign) continue;
						}
						
						PlaylistTracks = (ArrayList<?>) Playlist.get("Playlist Items"); // list of tracks in a playlist
						if (PlaylistTracks == null) {
							PMS.dbg("getiTunesFolder_in: Playlist name="+name+", has no entries --> Ignore");
							continue;
						}
						
						VirtualFolder pf = new VirtualFolder(Playlist.get("Name").toString(), null);
						pf.setDefaultRenderer(res.getDefaultRenderer());  //add by regzam, need for controll_subfolder
						pf.sort_enabled=true; //regzamod
						pf.rz_MetaSortType=PMS.SORT_NAME_NUM;
						
						if(true) {
						//if (PlaylistTracks != null) {
							for (Object t : PlaylistTracks) {
								HashMap<?, ?> td = (HashMap<?, ?>) t;
								track = (HashMap<?, ?>) Tracks.get(td.get("Track ID").toString());
								
								//if (track != null && track.get("Location").toString().startsWith("file://")) {
								//--> if track.get("Location") fail, then cause Exception!! and all will be abondoned.	
								
								if (track != null && track.get("Location") != null
									&& track.get("Location").toString().startsWith("file://")) {	//regzamod
																	
									URI tURI2 = new URI(track.get("Location").toString());
									RealFile file = new RealFile(new File(URLDecoder.decode(tURI2.toURL().getFile(), "UTF-8")));
									pf.addChild(file);
								} else {	//regzamod
									logger.warn("getiTunesFolder_in: Couldn't find Location, Track ID="
										 +td.get("Track ID").toString()
										 +", Folder="+Playlist.get("Name").toString()
										 +", Name="+(track==null?"null":track.get("Name").toString()));
								}
							}
						}
						res.addChild(pf);
					}
				} else {
					logger.warn("Could not find the iTunes file");
				}
			} catch (Exception e) {
				logger.error("Something went wrong with the iTunes Library scan: ", e);
			}
		}
		res.sotype=SO_ITUNE_SOLVED;	//regzamod, indicate iTunes folder & Child Creadted , TODO use more smart method
		if(PMS.rz_debug>1) {
			PMS.dbg("rz_ItunesFolder.resolve_in: Parse End, renderer="+rend);
		}
		return;
	}

	/**
	 * Returns the iTunes XML file. This file has all the information of the
	 * iTunes database. The methods used in this function depends on whether PMS
	 * runs on MacOsX or Windows.
	 * 
	 * @return (String) Absolute path to the iTunes XML file.
	 * @throws Exception
	 */
	private String getiTunesFile() throws Exception {
		String line = null;
		String iTunesFile = null;
		if (Platform.isMac()) {
			Process prc = Runtime.getRuntime().exec("defaults read com.apple.iApps iTunesRecentDatabases");
			BufferedReader in = new BufferedReader(new InputStreamReader(prc.getInputStream()));
			if ((line = in.readLine()) != null) {
				line = in.readLine(); // we want the 2nd line
				line = line.trim(); // remove extra spaces
				line = line.substring(1, line.length() - 1); // remove quotes and spaces
				URI tURI = new URI(line);
				iTunesFile = URLDecoder.decode(tURI.toURL().getFile(), "UTF8");
			}
			if (in != null) {
				in.close();
			}
		} else if (Platform.isWindows()) {
			Process prc = Runtime.getRuntime().exec("reg query \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\" /v \"My Music\"");
			BufferedReader in = new BufferedReader(new InputStreamReader(prc.getInputStream()));
			String location = null;
			while ((line = in.readLine()) != null) {
				final String LOOK_FOR = "REG_SZ";
				if (line.contains(LOOK_FOR)) {
					location = line.substring(line.indexOf(LOOK_FOR) + LOOK_FOR.length()).trim();
				}
			}
			if (in != null) {
				in.close();
			}
			if (location != null) {
				// add the itunes folder to the end
				location = location + "\\iTunes\\iTunes Music Library.xml";
				iTunesFile = location;
			} else {
				logger.info("Could not find the My Music folder");
			}
		}

		return iTunesFile;
	}


}
