/*
 * 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.
 */
//-----------------------------------------------------------------------------
// Regzamod specific class
// A kind of MetaFile for play tuning of according RealFile(Media body)
// Intended porposes are.. (include for future implements)
// 1) Partial play (partial cut_out from RealFile by start/stop time)
// 2) Sound tunings: sound_delay, volume etc.
// 3) Video tunings: aspect_ratio, zoom etc.
//-----------------------------------------------------------------------------
package net.pms.dlna;

import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.StringTokenizer;
import java.util.Calendar;

//need Java 1.7
//import java.nio.file.FileSystem;
//import java.nio.file.FileSystems;
//import java.nio.file.Path;	//regzamod

import net.pms.PMS;
import net.pms.formats.Format;
import net.pms.util.FileUtil;
import net.pms.util.ProcessUtil;
import net.pms.util.PMSUtil;
import net.pms.configuration.RendererConfiguration;
import net.pms.dlna.DVDISOTitle;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//public class  rz_PlayMetaFile extends RealFile {
public class  rz_PlayMetaFile extends RealFile implements DVDISOTitleIF {
	private static final Logger logger = LoggerFactory.getLogger(rz_PlayMetaFile.class);
	//private File my_metafile; 		// it's me (metafile)
	private boolean resolved1;
	private boolean resolved2;
	private boolean nameMnted;
	private DVDISOTitle dvdf;	//implemented obj container
	private int resname_pathadd_iso=PMS.getConfiguration().getRZ_resname_pathadd_iso();
	
	private String sname,sname0;
	// moved to DLNAResource, ugly params
	//private String title; 			// metafile params
	//boolean body_exists=false;
	//private int dvd_title_num;	//dvd title number(valid >=1)
	//private boolean isVfolder;
	//public boolean isDVDISO=false;
	//public String dvd_chapter_str;	//dvd chapter number string e.x. 1,2,1-5 
	//public String bodypath;
	
	public static String rsuffix="."+PMS.rz_ResumeFileSuffix;
	public static int MODE_PXM=1;	//for PlayMetafile, create pxm class & read params
	public static int MODE_PXF=2;	//for PlayProfile, only read params
	//public String WebOpts;

	//subclass constructor must exec super's constructor
	//if you don't explicitly call super(params)
	//then subclass constructor implicitly call super's constructor with "no param"
	
	//---- pxm in playlist that can designate name(title)
	public rz_PlayMetaFile(File meta, String name) {	
		const_body(meta, name);
		if(isDVDISO) {
			//PMS.dbg("rz_PlayMetaFile: create DVDISOTitle");
			this.dvdf=new DVDISOTitle(rz_Bodyfile, dvd_title_num, dvd_chapter_str);
			//this.dvdf.setName(sname);
		}
	}
	
	//---- Normal pxm that links to file/url
	public rz_PlayMetaFile(File meta, int meta_type) {
		this.meta_type=meta_type;
		const_body(meta, null);
		if(isDVDISO) {
			//PMS.dbg("rz_PlayMetaFile: create DVDISOTitle");
			this.rz_MetaDVDchapter=dvd_chapter_str;
			this.dvdf=new DVDISOTitle(rz_Bodyfile, dvd_title_num, dvd_chapter_str);
			//this.dvdf.setName(sname);  //don't set: preserve default name for later use
		}
	}
	
	//---- for Special use? create without metafile
	public rz_PlayMetaFile(File folder, String name, int dumy) {
		//rz_Metafile=folder;
		rz_Bodyfile=folder;
		rz_Bodypath=folder.getAbsolutePath();
		getConf().getFiles().add(rz_Bodyfile);
		getConf().setName(name);
		sname=name;
		sname0=name;
		setLastmodified(folder.lastModified());
		resolved1=true; //no need to read metafile
	}

	//--- for add path_part to dvdiso resume file name
	//this method handle only real path names
	//i.e can't handle dpname of paths changed by pxm/pxf
	private void rz_isoNameMnt() {
		if(nameMnted) return;
		if(resname_pathadd_iso==0) return;
		nameMnted=true;
		
		if(meta_type==2 && isDVDISO && sotype!=SO_DVDDEV && rz_Metafile2==null ) { //iso resume file
			DLNAResource pa=getParent();
			if(resname_pathadd_iso<0) {
				//path partadd done already by resume_save
				if(pa==null || !pa.isResumeFolderAll) { //not under resume_all --> delete pathpart
					sname=dvdf.getName();
					//sname0=sname;  //preserve title in sname0
					dname=sname;
				} else { //under resume_all --> noop: retain pathpart
					;  
				}
				return;
			}
			//resumeFile of dvdiso & target isn't Metafile-linked
			if(pa==null || !pa.isResumeFolderAll) { //not under resume_all
				sname=dvdf.getName();
			}
			else if(resname_pathadd_iso>0) {	//under resume_all --> add pathpart to name
				String pathadd=null;
				if(resname_pathadd_iso>=1) {
					pathadd=rz_Bodyfile.getName();
				}
				if(resname_pathadd_iso>=2) {
					pathadd=rz_Bodyfile.getParentFile().getName()+"/"+pathadd;
				}
				if(pathadd!=null)
					sname=pathadd+"/"+dvdf.getName();
				else
					sname=dvdf.getName();
			}
			sname0=sname;  //preserve sname0
			dname=sname;
		}
	}
	
	@Override
	public void setDispDate(long date) {
		rz_MetaDispDate=date;
	}
	@Override
	public long getDispDate() {
		if(rz_MetaDispDate>0) {		// designated date
			return rz_MetaDispDate;
		}
		else if(rz_MetaDispDate== -2) {  // date of link target
			if(rz_Bodyfile!=null) {
				return rz_Bodyfile.lastModified();
			}
		}
		return getLastmodified(); // date of me(metafile)
	}

	private void const_body(File meta, String name) {
		//---- must get path of link_target, at least
		sname=name;
		rz_Metafile=meta;		// memory me
		resolve_mparam(MODE_PXM,this,rz_Metafile,name);
		setLastmodified(meta.lastModified());
	}

	public boolean needReCreate() {
		
		if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: Start, name="+getName());
		
		//PMS.dbg("meta.needReCreate: Name="+getConf().getName());
		//PMS.dbg("meta.needReCreate: saved Lastmodified()="+getLastmodified());
		//PMS.dbg("meta.needReCreate: real  LastModified()="+rz_Metafile.lastModified());
		
		//metafile prefer reCreate insted of resolve, for update
		// cause delete the obj, why?
		if(rz_Bodyfile!=null) {
			if(!rz_MetaBodyExists && rz_Bodyfile.exists()) {
				if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-1(BodyFile now created) rc=true");
				return true;
			}
			if(rz_MetaBodyExists && !rz_Bodyfile.exists()) {
				if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-2(BodyFile now deleted)) rc=true");
				return true;
			}
		}
		if(rz_Metafile!=null) {
			if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-3");
			boolean b=(getLastmodified() < rz_Metafile.lastModified());
			if(b) {
				if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: true End-3(Metafile updated) "
					+", meta="+rz_Metafile.getPath()
					+", body="+rz_Bodyfile==null?"null":rz_Bodyfile.getPath()
				);
			}
			return (b);
		}
		else if(rz_Bodyfile!=null) {
			if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-4");
			return (getLastmodified() != rz_Bodyfile.lastModified());
		}
		if(meta_type==2) { //resumeFile
			if(rz_Profile!=null) {
				if(pxf_lastmodified != rz_Profile.lastModified()) {
					if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-5");
			 		return true;
				}
			}
			else { 
				// check if pxf exists under me --> Heavy check: to be refined
			 	File pxf=new File(getSrcPath()+"."+PMS.rz_ProfileSuffix);
			 	if(pxf.exists()) {
					if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-6");
			 		return true;
			 	}
			}
		}
		if(PMS.rz_debug>1) PMS.dbg("rz_PlayMetaFile.needReCreate: End-7");
		return false;
	}
	
	//@Override
	private boolean isFolder_r() {
		return (rz_Bodyfile!=null && rz_Bodyfile.isDirectory());
	}

	//@Override
	private boolean isValid_r() {
		// this is not perfect!! should re-create dlna object!!
		//PMS.dbg("MetaFile: isValid Called, bodyfile="+rz_Bodyfile);
		//if(!body_exists) {	
		//	return false;	// disappear from list --> not usefull
		//}
		if(false && needReCreate()) {
			if(!resolved1) {	//for test
				//resolve_mparam(MODE_PXM,this,rz_Metafile,null);
				resolved1 = true;
			}
			//PMS.dbg("---> needReCreate() is true, exec resolve_mparam, new bodyfile="+rz_Bodyfile);
		}
		super.isValid();
		return true;
	}
	
	public File getBodysParentFolder() {
		if(rz_Metafile==null) return null;
		return rz_Metafile.getParentFile();
	}
	
	@Override
	public DLNAMediaInfo getMedia() {	
		if(isDVDISO) {
			return this.dvdf.getMedia();
		}
		//returm media;	//will cause compile warnings 
		return super.getMedia();	
	}
	
	@Override
	public Format getExt() {	//regzamod, cause compile warnings
		if(isDVDISO) {
			if(dvdf!=null) {
				return this.dvdf.getExt();
			}
			return null;
		}
		//returm ext;	//will cause compile warnings 
		return super.getExt();
	}
	@Override
	protected void setExt(Format ext) {	//regzamod, cause compile warnings
		if(isDVDISO) {
			this.dvdf.setExt(ext);
		}
		else {
			//this.ext=ext;	//will cause compile warnings 
			super.setExt(ext);
		}
	}
	
	@Override
	public boolean isRefreshNeeded() {
		//called if isFolder()==true
		//PMS.dbg("rz_PlayMetafile.isRefreshNeeded: called");
		if(isDVDISO) {
			boolean ret=this.dvdf.isRefreshNeeded();
			if(ret) {
				resolved2=false;
			}
		}
		return super.isRefreshNeeded();
	}

	
	@Override
	public void resolve2 () {
		//update metafile (re-readin metafile)
		resolved1=false;
		resolved2=false;
		resolve();
	}
	
	@Override
	public void resolve () {
		//PMS.dbg("rz_PlayMetafile.resolve: called");
		double sttp_sav;
		// preserve play start_pos for resumeFile
		// to avoid overwritten by superClass
		sttp_sav=rz_PartPlaySttp;  

		if(isDVDISO) {
			boolean ret=this.dvdf.isRefreshNeeded();
			if(ret) resolved2=false;
			//PMS.dbg("rz_PlayMetafile.resolve: DVDISO isRefreshNeeded="+ret);
		}
		if(resolved2) return;
		resolved2=true;
		resolve_mparam(MODE_PXM,this,rz_Metafile,null);
		//super.resolve();
		
		if(isDVDISO) {
			//PMS.dbg("rz_PlayMetafile: call DVDISOTitle.resolve()");
			this.dvdf.resolve();
			//--- for dvdiso resume file name
			rz_isoNameMnt();
			/*
			if(rz_Bodyfile.exists()) {
				if(sname0!=null) {
					this.dvdf.setName(sname0);
				}
			}
			*/
		}
		else {
			super.resolve();
		}
		if(meta_type!=2) {  //not resume file
			rz_PartPlaySttp=sttp_sav;
		}
		
		if(!rz_MetaBodyExists && rz_MetaNotExistSuffix) {
			dname=sname+" (?)";
		}
		else {
			dname=sname;
		}
		
		if(isDVDISO) {
			//PMS.dbg("rz_PlayMetafile: dvdf.dlna="+this.dvdf);
			//PMS.dbg("rz_PlayMetafile: dvdf.getPlayer="+this.dvdf.getPlayer());
			DLNAMediaInfo m=dvdf.getMedia();
			//PMS.dbg("rz_PlayMetafile: dvdf.getMedia()="+m);
		}
		
		//PMS.dbg("rz_PlayMetafile.resolve: start");
		//if(rz_isPartPlay && getPlayer()== null && rz_PartPlayEndp>0) {
		if(rz_isPartPlay && getPlayer()== null) {
			if(rz_PartPlayEndp>0 || PMS.rz_direct_seek==false) {
				//PMS.dbg("rz_layMetafile: partial play of Ditect, with end_point --> set Player ");
				setPlayer(player2);
			}
			else {
				//PMS.dbg("rz_layMetafile: partial play of Ditect, without end_point --> leave Player null");
			}
		}
		
		//some maintenance of params
		if(PMS.rz_debug>1) {
			PMS.dbg("rz_PlayMetafile.resolve:"
				+", meta_type="+meta_type
				+", rz_isPartPlay="+rz_isPartPlay
				+", rz_PartPlaySttp_prev="+sttp_sav
				+", rz_PartPlaySttp="+rz_PartPlaySttp
				+", rz_PartPlayEndp="+rz_PartPlayEndp
			);
		}
		
		if(rz_isPartPlay==true) {
			if(rz_PartPlayEndp==0) {
				// Endp not defined
				if(getMedia()!=null) {
					rz_PartPlayEndp=getMedia().getDurationInSeconds();
				}
				else {
					PMS.dbg("rz_PlayMetafile.resolve: can't get media duration, Metafile="+rz_Metafile);
					rz_PartPlayEndp=1800d;
				}
			}
			rz_PartPlayDuration=rz_PartPlayEndp - rz_PartPlaySttp;
			setSplitRange(new Range.Time(rz_PartPlaySttp,rz_PartPlayEndp));
		}
		if(PMS.rz_debug>1) {
			PMS.dbg("Resolve: Metafile="+rz_Metafile+", Bodyfile="+rz_Bodyfile);
			PMS.dbg("meta_param rz_SoundDelay="+rz_SoundDelay[0]+", PartPlay="+rz_isPartPlay+", sp="+rz_PartPlaySttp+", ep="+rz_PartPlayEndp);
		}
	}

	//for other class with pxf
	//read pxf
	public static void pxf_read(DLNAResource dlnp,File pxf) {
		//PMS.dbg("pxf_read: called, pxf="+pxf);
		resolve_mparam_read(MODE_PXF,dlnp,null,pxf,0);
		//dlnp.rz_Metafile=pxf;
		dlnp.toString_sb=null; //clear cache of toString()
		dlnp.rz_Profile=pxf;
		dlnp.pxf_lastmodified=pxf.lastModified();
	}

	//for other class with pxf
	//resolve pxf
	public static void pxf_resolve(DLNAResource dlnp, int mode) {
		//PMS.dbg("pxf_resolve: called, dlna="+dlnp.getName());
		if(mode==1) {  // read pxf
			File pxf=null;
			boolean readpxf=false;
			if(dlnp.rz_Profile!=null) {
				if(dlnp.pxf_lastmodified != dlnp.rz_Profile.lastModified()) {
					//PMS.dbg("pxf_resolve: pxf updated, need resolve");
			 		readpxf=true;
					pxf=dlnp.rz_Profile;
				}
			}
			else { 
				// check if pxf exists under me --> Heavy check: to be refined
			 	pxf=new File(dlnp.getSrcPath()+"."+PMS.rz_ProfileSuffix);
			 	if(pxf.exists()) {
			 		readpxf=true;
			 	}
			}
			if(readpxf) {
		 		initMetaParams(dlnp);
				pxf_read(dlnp,pxf);
				dlnp.pxf_resolved=false;
			}

			if(dlnp.pxf_resolved) return;
			//PMS.dbg("pxf_resolve: not resolved yet, exec resolve");
		}
		
		if(dlnp.rz_isPartPlay==true) {
			if(dlnp.rz_PartPlayEndp==0) {
				// Endp not defined
				if(dlnp.getMedia()!=null) {
					dlnp.rz_PartPlayEndp=dlnp.getMedia().getDurationInSeconds();
				}
				else {
					PMS.dbg("rz_PlayMetafile.pxf_resolve: can't get media duration, Metafile="+dlnp.rz_Profile);
					dlnp.rz_PartPlayEndp=1800d;
				}
			}
			dlnp.rz_PartPlayDuration=dlnp.rz_PartPlayEndp - dlnp.rz_PartPlaySttp;
			dlnp.setSplitRange(new Range.Time(dlnp.rz_PartPlaySttp,dlnp.rz_PartPlayEndp));
		}
		dlnp.pxf_resolved=true;
	}
	
	//read Metafile from my class
	private void resolve_mparam(int mode,DLNAResource dlnp,File meta,String name) {
		if(resolved1) return;
		resolve_mparam_read(mode,dlnp,name,meta,0);
		dlnp.toString_sb=null; //clear cache of toString()
		resolved1=true;
	}
	
	private static void resolve_mparam_read(int mode,DLNAResource dlnp,String name_in,File metafile,int callcnt) {
		int	radix;
		String str=null;
		List<File> path_list = new ArrayList<File>();
		rz_PlayMetaFile pxmp=null;

		if(PMS.rz_debug>1) PMS.dbg("resolve_mparam_read: Start, name="+dlnp.getName()+", name_in="+name_in+", Metafile="+metafile);
		if(mode==MODE_PXM) {
			pxmp=(rz_PlayMetaFile)dlnp;
		}
				
		//--- followings only for pxm file
		String title=null;
		String sname=null;
		String sname0=null;
		String bodypath=null;
		//String dvd_chapter_str=null;
		//int dvd_title_num=0;
		//boolean isDVDISO=false;
		//boolean isVfolder=false;
		//boolean body_exists=false;
		//---
		
		/*
		if(mode==MODE_PXM) {
			//read-in pxm specific class valiables
			pxmp=(rz_PlayMetaFile)dlnp;
			sname=pxmp.sname;
			sname0=pxmp.sname0;
			body_exists=pxmp.body_exists;  //need
			bodypath=pxmp.bodypath;
			dvd_chapter_str=pxmp.dvd_chapter_str;
			dvd_title_num=pxmp.dvd_title_num;
			isDVDISO=pxmp.isDVDISO;
			isVfolder=pxmp.isVfolder;
		}
		*/
		
		//title=null;
		//body_exists=false;
		//--- read metafile contents
		String line=null;
		try {
			FileInputStream fis=new FileInputStream(metafile);
			BufferedReader br;
			if(metafile.getName().endsWith(PMS.rz_ResumeFileSuffix)) {
				br = new BufferedReader(new InputStreamReader(fis,"UTF-8"));
			}
			else {
				String enc=PMS.getConfiguration().getRZ_MetafileEncode();
				if(enc.equals("AutoDetect")) {	//regzamod
					int skip_bytes[]={0};
					enc=FileUtil.rzCharaCodeDetect(metafile.getPath(),skip_bytes);
					
					if(PMS.rz_debug>1) PMS.dbg("PlayMetafile: AutoDetect enc="+enc+", meta="+metafile.getPath());
					if(enc==null) {
						enc=PMS.get().getDefaultTextEncode();
						if(PMS.rz_debug>1) {
							logger.warn("rz_PlayMetaFile: failed autodetect of text-encode, use default enc="+enc+", meta="+metafile.getName());
						}
					}
					if(skip_bytes[0]>0) {	// Unicode BOM exists
						fis.skip(skip_bytes[0]);
					}
				}
				br = new BufferedReader(new InputStreamReader(fis,enc));
			}
			while ((line = br.readLine()) != null) {
				line = line.trim();
				if(line.startsWith("#") || line.length()<=0) {
					continue;
				}
				//if(line.startsWith("metafile=") && callcnt==0) {
				if(line.startsWith("metafile=")) {
					if(callcnt==0) {
						//callcnt==0: avoid infinit recursive calls
						String metapath=line.substring(9).trim();
						if(metapath!=null && metapath.contains("\"")) {
							StringTokenizer st = new StringTokenizer(metapath,"\"");
							if(st.hasMoreTokens()) metapath=st.nextToken();
						}
						if(metapath!=null) {
							File metaf=new File(metapath);
							if(metaf.isFile()) {
								//read linked-metafile
								//PMS.dbg("rz_PlayMetafile.resolve_mparam_read: read linked metafile="+metaf);
								dlnp.rz_Metafile2=metaf;
								resolve_mparam_read(mode,dlnp,name_in,metaf,1);
							}
						}
					}
					else {
						logger.warn("Metafile: Ignore param 'metafile' that once appeared, meta="+metafile.getPath());
					}
				}
				else if(line.startsWith("path=")) {
					bodypath=line.substring("path=".length()).trim();
					//trim double-quotations
					if(bodypath!=null && bodypath.contains("\"")) {
						StringTokenizer st = new StringTokenizer(bodypath,"\"");
						if(st.hasMoreTokens()) bodypath=st.nextToken();
					}
					if(!bodypath.isEmpty()) {
						if(bodypath.endsWith(rsuffix) && callcnt==0) {	
							//path is metafile
							File metaf=new File(bodypath);
							if(metaf.isFile()) {
								//read linked-metafile
								//PMS.dbg("rz_PlayMetafile.resolve_mparam_read: read linked meta="+metaf);
								dlnp.rz_Metafile2=metaf;
								resolve_mparam_read(mode,dlnp,name_in,metaf,1);
								//bodypath=rz_Bodypath; //memory results
							}
						}
					}
				}
				else if(line.startsWith("path_vf=")) {  //for virtual multi-folder
					String path=line.substring("path_vf=".length()).trim();
					if(path!=null && path.contains("\"")) {//trim double-quotations
						StringTokenizer st = new StringTokenizer(path,"\"");
						if(st.hasMoreTokens()) path=st.nextToken();
					}
					if(!path.isEmpty()) {
						File f=new File(path);
						//relative path not supported
						if(f.exists()) {
							//PMS.dbg("Metafile: path_vf="+path);
							path_list.add(f);
						}
						else {
							logger.warn("Metafile: path_vf's path Not found="+path+", meta="+metafile.getPath());
							//path_list.add(f);  // add, even if not exists
						}
					}
				}
				else if(line.startsWith("vstream=")) {
					str=line.substring("vstream=".length()).trim();
					if(str != null && !str.isEmpty()) {
						bodypath=str;
						dlnp.sotype=SO_VIDEO_STREAM;
						//trim double-quotations
						if(bodypath!=null && bodypath.contains("\"")) {
							StringTokenizer st = new StringTokenizer(bodypath,"\"");
							if(st.hasMoreTokens()) bodypath=st.nextToken();
						}
					}
					if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: vstream, bodypath="+bodypath);
				}
				else if(line.startsWith("web_opts=")) {
					str=line.substring("web_opts=".length()).trim();
					if(str != null && !str.isEmpty()) {
						dlnp.wmed_opts=str;
						//PMS.dbg("metafile: duration="+dlnp.wmed_duration);
					}
				}
				else if(line.startsWith("duration=")) {
					str=line.substring("duration=".length()).trim();
					if(str != null && !str.isEmpty()) {
						dlnp.wmed_duration=(float)PMSUtil.convertTime(str);
						//PMS.dbg("metafile: duration="+dlnp.wmed_duration);
					}
				}
				else if(line.startsWith("title=")) {
					str=line.substring("title=".length()).trim();
					if(str != null && !str.isEmpty())  title=str;
				}
				else if(line.startsWith("disp_date=")) {
					str=line.substring("disp_date=".length()).trim();
					if(str != null && !str.isEmpty()) {
						int yy=0;int mm=0;int dd=0;int hh=0;int min=0;int sec=0;
						Calendar cal=Calendar.getInstance();
						String[] dates=str.split("[/\\: ]");
						boolean setf=false;
						//PMS.dbg("dates.length="+dates.length+", disp_date="+str);
						cal.clear();
						if(dates.length==3) {
							 setf=true;
							 yy=Integer.parseInt(dates[0]);
							 mm=Integer.parseInt(dates[1])-1; //why? -1
							 dd=Integer.parseInt(dates[2]);
							 cal.set(yy,mm,dd);
						}
						else if(dates.length==5) {
							 setf=true;
							 yy=Integer.parseInt(dates[0]);
							 mm=Integer.parseInt(dates[1])-1; //why? -1
							 dd=Integer.parseInt(dates[2]);
							 hh=Integer.parseInt(dates[3]);
							 min=Integer.parseInt(dates[4]);
							 cal.set(yy,mm,dd,hh,min);
						}
						else if(dates.length==6) {
							 setf=true;
							 yy=Integer.parseInt(dates[0]);
							 mm=Integer.parseInt(dates[1])-1; //why? -1
							 dd=Integer.parseInt(dates[2]);
							 hh=Integer.parseInt(dates[3]);
							 min=Integer.parseInt(dates[4]);
							 sec=Integer.parseInt(dates[5]);
							 cal.set(yy,mm,dd,hh,min,sec);
						}
						if(setf) {
							 dlnp.rz_MetaDispDate=cal.getTimeInMillis();
						}
						else if(str.equals("-2")) {
							 dlnp.rz_MetaDispDate=-2;
						}
						else {
							logger.warn("Metafile: Illegal disp_date="+str+", meta="+metafile.getPath());
						}
					}
				}
				else if(line.startsWith("start_pos=")) {
					PMS.dbg("got start_pos="+dlnp.rz_PartPlaySttp);
					str=line.substring("start_pos=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_PartPlaySttp=PMSUtil.convertTime(str);
				}
				else if(line.startsWith("stop_pos=")) {
					str=line.substring("stop_pos=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_PartPlayEndp=PMSUtil.convertTime(str);
				}
				else if(line.startsWith("sound_delay=")) {
					str=line.substring("sound_delay=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_SoundDelay[0]=PMSUtil.convertTime(str);
				}
				else if(line.startsWith("aspect=")) {
					str=line.substring("aspect=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaAspect=str;
				}
				else if(line.startsWith("zoom=")) {
					str=line.substring("zoom=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaZoom[0]=Double.parseDouble(str);
				}
				else if(line.startsWith("shift=")) {
					str=line.substring("shift=".length()).trim();
					if(str != null && !str.isEmpty()) {
						String[] margs=str.split(",");
						if(margs.length<2) {
							logger.warn("Metafile: Illegal shift_value="+str+", meta="+metafile.getPath());
							continue;
						}
						dlnp.rz_MetaShift[0]=Double.parseDouble(margs[0]);
						dlnp.rz_MetaShift[1]=Double.parseDouble(margs[1]);
					}
				}
				else if(line.startsWith("sound_volume=")) {
					str=line.substring("sound_volume=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaSoundVolume=(int)Float.parseFloat(str);
				}
				else if(line.startsWith("sound_sync=")) {
					str=line.substring("sound_sync=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaSoundSync=(int)Float.parseFloat(str);
				}
				//---- override TsMuxerVideo's remux type
				else if(line.startsWith("trans_type=")) {	//transcode type
					str=line.substring("trans_type=".length()).trim();
					if(str != null && !str.isEmpty()) {	// {direct|remux|trans}
						if(str.equals("direct")) 		dlnp.rz_MetaTransType[0]=PMS.ENC_DIRECT;
						else if(str.equals("remux"))	dlnp.rz_MetaTransType[0]=PMS.ENC_REMUX;
						else if(str.equals("trans"))	dlnp.rz_MetaTransType[0]=PMS.ENC_TRANSCODE;
						else {
							logger.warn("Metafile: Illegal trans_type="+str+", meta="+metafile.getPath());
						}
					}
				}
				else if(line.startsWith("trans_proc=")) { 	// {213|222|333},1:mencoder,2:ffmpeg,3:tsmuxer
					//override RZ_RemuxExtractByFfmpeg in renderer.conf
					str=line.substring("trans_proc=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaTransProc[0]=(int)Float.parseFloat(str);
				}
				else if(line.startsWith("remux_proc=")) { 	// {213|222|333},1:mencoder,2:ffmpeg,3:tsmuxer
					//override RZ_RemuxExtractByFfmpeg in renderer.conf
					str=line.substring("remux_proc=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaRemuxProc[0]=(int)Float.parseFloat(str);
				}
				else if(line.startsWith("trans_prog=")) { 	// {213|222|333},1:mencoder,2:ffmpeg,3:tsmuxer
					//override RZ_RemuxExtractByFfmpeg in renderer.conf
					str=line.substring("trans_prog=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaTransProg[0]=str;
				}
				else if(line.startsWith("remux_prog=")) { 	// {213|222|333},1:mencoder,2:ffmpeg,3:tsmuxer
					//override RZ_RemuxExtractByFfmpeg in renderer.conf
					str=line.substring("remux_prog=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaRemuxProg[0]=str;
				}
				else if(line.startsWith("trans_format=")) {	//transcode format(container type)
					str=line.substring("trans_format=".length()).trim();
					if(str != null && !str.isEmpty()) {	// {direct|remux|trans}
						if(str.equals("mpegps")) 		dlnp.rz_MetaTransFormat[0]=PMS.TRS_MPEGPS;
						else if(str.equals("mpegts"))	dlnp.rz_MetaTransFormat[0]=PMS.TRS_MPEGTS;
						else if(str.equals("mpegts2"))	dlnp.rz_MetaTransFormat[0]=PMS.TRS_MPEGTS2;
						else if(str.equals("m2ts"))	dlnp.rz_MetaTransFormat[0]=PMS.TRS_M2TS;
						else {
							logger.warn("Metafile: Illegal trans_format="+str+", meta="+metafile.getPath());
						}
					}
				}
				else if(line.startsWith("remux_format=")) {	//remux format(container type)
					str=line.substring("remux_format=".length()).trim();
					if(str != null && !str.isEmpty()) {	// {direct|remux|trans}
						if(str.equals("mpegts")) 		dlnp.rz_MetaRemuxFormat[0]=PMS.TRS_MPEGPS;
						else if(str.equals("m2ts"))	dlnp.rz_MetaRemuxFormat[0]=PMS.TRS_M2TS;
						else {
							logger.warn("Metafile: Illegal remux_format="+str+", meta="+metafile.getPath());
						}
					}
				}
				else if(line.startsWith("mencoder_opt=")) {	//mencoder options
					str=line.substring("mencoder_opt=".length()).trim();
					if(str != null && !str.isEmpty()) dlnp.rz_MetaMencoderOpt[0]=str;
				}
				else if(line.startsWith("mencoder_opta=")) {	//mencoder options (audio only for m2ts)
					str=line.substring("mencoder_opta=".length()).trim();
					if(str != null && !str.isEmpty()) dlnp.rz_MetaMencoderOptA[0]=str;
				}
				else if(line.startsWith("ffmpeg_opt=")) {	//ffmpeg options (for remux)
					str=line.substring("ffmpeg_opt=".length()).trim();
					if(str != null && !str.isEmpty()) dlnp.rz_MetaFFmpegOpt[0]=str;
				}
				
				//---- followings are low signifcant
				else if(line.startsWith("seek_audio_delay=")) {
					str=line.substring("seek_audio_delay=".length()).trim();
					if(str != null && !str.isEmpty()) dlnp.rz_SeekAudioDelay=PMSUtil.convertTime(str);
				}
				else if(line.startsWith("seek_audio_magnify=")) {
					str=line.substring("seek_audio_magnify=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_SeekAudioMagnify=Double.parseDouble(str);
				}
				else if(line.startsWith("track_v=")) {
					str=line.substring("track_v=".length()).trim();
					if(str != null && !str.isEmpty()) {
						 //parseInt can't auto judge radix !!
						 radix=10;	//decimal
						 if(str.toLowerCase().startsWith("0x")) {
						 	 str=str.substring(2);
						 	 radix=16;	//hex
						 }
						 dlnp.rz_MetaChannel_v=Integer.parseInt(str,radix);
					}
				}
				else if(line.startsWith("track_a=")) {
					str=line.substring("track_a=".length()).trim();
					if(str != null && !str.isEmpty()) {
						 //parseInt can't auto judge radix !!
						 radix=10;	//decimal
						 if(str.toLowerCase().startsWith("0x")) {
						 	 str=str.substring(2);
						 	 radix=16;	//hex
						 }
						 dlnp.rz_MetaChannel_a=Integer.parseInt(str,radix);
					}
				}
				else if(line.startsWith("dlna_prof=")) {
					str=line.substring("dlna_prof=".length()).trim();
					if(str != null && !str.isEmpty()) {
						String[] margs=str.split(",");
						if(margs.length>=1) {
							dlnp.rz_MetaDlnaProf[0]=margs[0];
						}
						if(margs.length>=2) {
							dlnp.rz_MetaDlnaOp[0]=margs[1];
						}
						//PMS.dbg("dlna_prof: prof="+dlnp.rz_MetaDlnaProf[0]+"Op="+dlnp.rz_MetaDlnaOp[0]);
					}
				}
				else if(line.startsWith("mime_type=")) {
					str=line.substring("mime_type=".length()).trim();
					if(str != null && !str.isEmpty())  dlnp.rz_MetaMimeType[0]=str;
					//PMS.dbg("mime_type="+dlnp.rz_MetaMimeType[0]);
				}
				else if(line.startsWith("sort_type=")) {
					str=line.substring("sort_type=".length()).trim();
					if(str != null && !str.isEmpty()) {
						int sort_type=PMS.rz_SortTypeString2id(1,str);
						if(sort_type==PMS.SORT_INVALID) {
							logger.warn("Metafile: Unknown sort_type="+str+", meta="+metafile.getPath());
						}
						else {
							dlnp.rz_MetaSortType=sort_type;
							dlnp.doSort=true;
						}
					}
					//PMS.dbg("sort_type="+dlnp.rz_MetaSortType);
				}
				else if(line.startsWith("sort_recursive=")) {
					str=line.substring("sort_recursive=".length()).trim();
					if(str.equals("true")) {
						dlnp.rz_MetaSortRecursive=true;
					}
					//PMS.dbg("Metafile: sort_recursive="+dlnp.rz_MetaSortRecursive+", meta="+metafile.getPath());
				}
				else if(line.startsWith("visual_clip_path=")) {
					str=line.substring("visual_clip_path=".length()).trim();
					if(str != null && !str.isEmpty()) {
						if(str.equals("default")) {
							dlnp.rz_VisualClipPath=null;
						}
						dlnp.rz_VisualClipPath=str;
					}
					//PMS.dbg("visual_clip_path="+dlnp.rz_VisualClipPath);
				}
				else if(line.startsWith("dvd_title_num=")) {
					str=line.substring("dvd_title_num=".length()).trim();
					if(str != null && !str.isEmpty()) {
						dlnp.dvd_title_num=Integer.parseInt(str);
						//PMS.dbg("dvd_title_num="+dlnp.dvd_title_num);
					}
				}
				else if(line.startsWith("dvd_chapter_num=")) {
					str=line.substring("dvd_chapter_num=".length()).trim();
					if(str != null && !str.isEmpty()) {
						//dvd_title_num=Integer.parseInt(str);
						dlnp.dvd_chapter_str=str;
						//PMS.dbg("dvd_chapter_no="+dvd_chapter_str);
					}
				}
				else {
					logger.warn("Metafile: Unknown params="+line+", meta="+metafile.getPath());
				}
			}
			br.close();
		} catch (NumberFormatException e) {
			if(PMS.rz_debug>0) logger.error(null, e);
			logger.warn("Metafile: NumberFormat Error, line="+line+", meta="+metafile.getPath());
		} catch (IOException e) {
			logger.error(null, e);
		}
		
		//---- Now, all params readed in -----------------
		if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: callcnt="+callcnt+", old Bodypath="+dlnp.rz_Bodypath+", new bodypath="+bodypath);
		if(callcnt==0) {
			if(dlnp.rz_PartPlaySttp!=0 || dlnp.rz_PartPlayEndp!=0 || dlnp.rz_MetaRemuxProc[0]>0|| dlnp.rz_MetaSoundVolume>=0) {
				//PMS.dbg("rz_PlayMetafile.resolve_mparam: set rz_PartPlaySttp="+rz_PartPlaySttp);
				dlnp.rz_isPartPlay=true;
				dlnp.rz_PartPlayDuration=dlnp.rz_PartPlayEndp - dlnp.rz_PartPlaySttp;
				dlnp.setSplitRange(new Range.Time(dlnp.rz_PartPlaySttp,(dlnp.rz_PartPlayEndp==0?null:dlnp.rz_PartPlayEndp)));
				//PMS.dbg("rz_PlayMetafile.resolve_mparam: splitRange="+getSplitRange());
			}

			//---- create DLNAresource of the metafile
			//CharSequence charSeq = ":/?";
			//if(callcnt==0) {
			if(dlnp.rz_Bodypath==null) {
				if(pxmp!=null && path_list.size()>0) {
					if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: type-1, for virtual multi-folder");
					//---- for virtual multi-folder
					//if(pxmp.rz_Bodyfile!=null && pxmp.rz_Bodyfile.isDirectory()) {
					if(true) {
						dlnp.isVfolder=true;
						//PMS.dbg("Metafile: path_vf="+path_list);
						if(pxmp.rz_Bodyfile==null) {
							pxmp.rz_Bodyfile=path_list.get(0);
							pxmp.rz_MetaBodyExists=true;
							pxmp.rz_Bodypath=pxmp.rz_Bodyfile.getAbsolutePath();
						}
						for(File f : path_list) {
							pxmp.getConf().getFiles().add(f);
						} 
					}
					else {
						logger.warn("Metafile: meta="+metafile.getPath()
							+", 1st path isn't directory, so ignore path_vf="+path_list);
					}
				}
				else if(dlnp.sotype==SO_VIDEO_STREAM) {
					if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: type-2, disignated SO_VIDEO_STREAM");
					dlnp.rz_Bodypath=bodypath;
				}
				else if(bodypath!= null && bodypath.contains("://")) {
					if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: type-3, judged SO_VIDEO_STREAM");
					dlnp.sotype=SO_VIDEO_STREAM;
					dlnp.rz_Bodypath=bodypath;
				}
				else {
					if(bodypath!= null) {
						//check if DVDSISO
						dlnp.rz_Bodyfile= new File(bodypath);
						String name_wk=dlnp.rz_Bodyfile.getName().toLowerCase();
						if(dlnp.dvd_title_num>0) {
							if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: type-4, DVDISO");
							if(dlnp.rz_Bodyfile.isFile() && (name_wk.endsWith(".iso")||name_wk.endsWith(".img"))) {
								//PMS.dbg("rz_PlayMetafile: seems to be DVDISO, path="+bodypath);
								dlnp.isDVDISO=true;
							}
							else if(name_wk.equals("video_ts")) {
								//PMS.dbg("rz_PlayMetafile: seems to be DVDISO, path="+bodypath);
								dlnp.isDVDISO=true;
								dlnp.sotype=SO_DVDDEV;	//seems to be real DVD media
							}
							if(!dlnp.rz_Bodyfile.exists()) {
								dlnp.rz_MetaBodyExists=false;
							}
							if(pxmp!=null && !pxmp.resolved1) {
								//pxmp.getConf().getFiles().add(pxmp.rz_Bodyfile);
							}
						}
						else if(dlnp.rz_Bodyfile.isAbsolute()) {
							if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: type-5a, Normal File with AbsolutePath");
							//PMS.dbg("seems to be normal absolute path="+bodypath);
							//PMS.dbg("       dlnp.rz_Bodyfile.exists()="+dlnp.rz_Bodyfile.exists());
							//PMS.dbg("       resolved1="+resolved1);
							if(!dlnp.rz_Bodyfile.exists()) {
								dlnp.rz_MetaBodyExists=false;
							}
							if(pxmp!=null && !pxmp.resolved1) {
								//PMS.dbg("getConf.add path="+pxmp.rz_Bodyfile);
								pxmp.getConf().getFiles().add(pxmp.rz_Bodyfile);
							}
						}
						else {	//relative path?
							if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: type-5b, Normal File with RealativePath");
							//PMS.dbg("seems to be relative path="+bodypath);
							try {	
								String pa_path=metafile.getParentFile().getCanonicalPath();
								bodypath=pa_path+"/"+bodypath;
								
								//PMS.dbg("rz_PlayMetafile: Metafile="+metafile.getPath()+", name="+dlnp.getName()+", bodypath="+bodypath);
								dlnp.rz_Bodyfile= new File(bodypath);
								//make dlnp.rz_Bodyfile have CanonicalPath
								bodypath=dlnp.rz_Bodyfile.getCanonicalPath();
								dlnp.rz_Bodyfile= new File(bodypath);
								//PMS.dbg("fullpath="+bodypath);
								
								if(!dlnp.rz_Bodyfile.exists()) {
									dlnp.rz_MetaBodyExists=false;
								}
								if(pxmp!=null && !pxmp.resolved1) {
									//PMS.dbg("getConf.add path="+pxmp.rz_Bodyfile);
									pxmp.getConf().getFiles().add(pxmp.rz_Bodyfile);
								}
							} catch (IOException e) {
								logger.error("rz_PlayMetafile: meta="+metafile.getPath()+", IOExecption-1: ", e.getMessage());
							}
						}
						if(!dlnp.rz_MetaBodyExists) {
							if(dlnp.isDVDISO) {
								//often occurable when not inserted
							}
							else {
								logger.error("Metafile: body_path not exists. meta="+metafile.getPath()+", path="+bodypath);
							}
						}
						dlnp.rz_Bodypath=bodypath;
					}
					else if(mode==MODE_PXM){
						//dlnp.rz_Bodyfile=null;
						logger.error("Metafile: body_path not defined, meta="+metafile.getPath());
					}
					if(pxmp!=null && !dlnp.rz_MetaBodyExists && !pxmp.resolved1) {
						// go-on add, need for PMS list it
						//pxmp.getConf().getFiles().add(metafile); // direct play doesn't close the file!! why?
						//File dummy=new File(":@");
						//pxmp.getConf().getFiles().add(dummy);
						pxmp.setPlayer(null);pxmp.player2=null;	//to avoid Unknown Errors
					}
				}
			}
		
			//---- set metafile's name (to be displayed on list)-----
			if(name_in!=null) {
				sname=name_in;
				dlnp.dname=sname;
			}
			else {
				if(title!=null) { //test
					//PMS.dbg("rz_layMetaFile.resolve_mparam_read: dlnp="+dlnp);
					sname=title;
					//dlnp.rz_MetaTitle=title; // who use this ??
					dlnp.dname=title;
				}
				else {
					sname=metafile.getName();
				}
			}
				

			sname0=sname;  //save original
			if(dlnp.sotype!=SO_VIDEO_STREAM) {
				if(!dlnp.rz_MetaBodyExists && dlnp.rz_MetaNotExistSuffix) {
					//rename may cause folder/file missmatch near this
					//sname=sname0+" (?)";
				}
			}
			
			//---- write back to target dlna
			//dlnp.rz_MetaBodyExists=body_exists;
			//dlnp.isVfolder=isVfolder;
			//dlnp.isDVDISO=isDVDISO;
			//dlnp.dvd_title_num=dvd_title_num;	//dvd title number(valid >=1)
			//dlnp.dvd_chapter_str=dvd_chapter_str;	//dvd chapter number string e.x. 1,2,1-5 
			//dlnp.setName(sname);
			//dlnp.dname=sname;
			if(pxmp!=null) {
				pxmp.sname0=sname0;
				pxmp.sname=sname;
				pxmp.dname=sname;
			}

		}
		
		if(PMS.rz_debug>2) {
			PMS.dbg("==== Metafile meta="+(metafile==null?"null":metafile.getPath()));
			PMS.dbg("rz_Bodyfile="+dlnp.rz_Bodyfile);
			PMS.dbg("title="+title+", name(displayed)="+sname);
			PMS.dbg("rz_PartPlaySttp="+dlnp.rz_PartPlaySttp+", rz_PartPlayEndp="+dlnp.rz_PartPlayEndp);
			PMS.dbg("rz_SoundDelay="+dlnp.rz_SoundDelay[0]+", rz_MetaAspect"+dlnp.rz_MetaAspect);
			PMS.dbg("rz_MetaSoundVolume="+dlnp.rz_MetaSoundVolume+", rz_MetaZoom"+dlnp.rz_MetaZoom);
			PMS.dbg("rz_SeekAudioDelay="+dlnp.rz_SeekAudioDelay+",rz_SeekAudioMagnify="+dlnp.rz_SeekAudioMagnify);
			PMS.dbg("rz_MetaSoundSync="+dlnp.rz_MetaSoundSync);
			PMS.dbg("rz_MetaTransType="+dlnp.rz_MetaTransType[0]+",rz_MetaRemuxProc="+dlnp.rz_MetaRemuxProc[0]);
			PMS.dbg("rz_MetaChannel_v="+dlnp.rz_MetaChannel_v+", rz_MetaChannel_a"+dlnp.rz_MetaChannel_a);
		}
		//resolved1=true;
		//super.resolve_fparam(metafile);
		if(PMS.rz_debug>2) PMS.dbg("PlayMetafile: End, name="+dlnp.getName()+", name_in="+name_in+", Metafile="+metafile);

	}

	public static DLNAResource managePxm(File meta, DLNAResource pa, int meta_type) {
		
		DLNAResource dch=null;
		rz_PlayMetaFile pxm=new rz_PlayMetaFile(meta,meta_type);
		//PMS.dbg("PlayMetafile.managePxm: pxm.sotype==SO_VIDEO_STREAM, time.Range="+pxm.getSplitRange());
		//PMS.dbg("PlayMetafile.managePxm: rz_isPartPlay="+pxm.rz_isPartPlay+", rz_PartPlayDuration="+pxm.rz_PartPlayDuration);
		//PMS.dbg("PlayMetafile.managePxm: rz_PartPlaySttp="+pxm.rz_PartPlaySttp+", rz_PartPlayEndp="+pxm.rz_PartPlayEndp);
		
		if(pxm.sotype==SO_VIDEO_STREAM) {
			//PMS.dbg("Mapfile.managePxm: Seems WebVideoStream, name="+pxm.getName()+",path="+pxm.rz_Bodypath);
			String thumbURL=null;
			WebVideoStream ch=new WebVideoStream(pxm.getName(), pxm.rz_Bodypath, thumbURL);
			
			copyMetaParams(pxm,ch);
			if(pa!=null) pa.addChild(ch);
			
			//misc. resolve, shuld be refined.
			if(pxm.wmed_opts!=null) {
				ch.setUrlParamsString(pxm.wmed_opts);
			}
			if(ch.getMedia()==null) ch.setMedia(new DLNAMediaInfo());
			ch.getMedia().setDuration(new Double(ch.wmed_duration));
			ch.getMedia().setMediaparsed(true); //fake, only duration setted
			if(ch.rz_PartPlaySttp>0) {
				if(ch.rz_PartPlayEndp==0) ch.rz_PartPlayEndp=ch.wmed_duration;
				ch.rz_PartPlayDuration=ch.rz_PartPlayEndp - ch.rz_PartPlaySttp;
				ch.setSplitRange(new Range.Time(ch.rz_PartPlaySttp,ch.rz_PartPlayEndp));
			}
			dch=(DLNAResource)ch;
			//PMS.dbg("PlayMetafile.managePxm: ch.sotype==SO_VIDEO_STREAM, duration="+ch.wmed_duration+", time.Range="+ch.getSplitRange());
			//PMS.dbg("PlayMetafile.managePxm: rz_isPartPlay="+ch.rz_isPartPlay+", rz_PartPlayDuration="+ch.rz_PartPlayDuration);
			//PMS.dbg("PlayMetafile.managePxm: rz_PartPlaySttp="+ch.rz_PartPlaySttp+", rz_PartPlayEndp="+ch.rz_PartPlayEndp);
		}
		else {
			if(pa!=null) pa.addChild(pxm);
			dch=(DLNAResource)pxm;
		}
		return dch;
	}
	
	private static void copyMetaParams(DLNAResource src, DLNAResource dest) {
		//copy rz_MetaXXXX member variables
		//---- DLNA Params
		dest.sotype = src.sotype;
		dest.meta_type = src.meta_type;
		dest.setSplitRange(src.getSplitRange());
		dest.setLastmodified(src.getLastmodified());
		
		//---- PlayMetafile Params
		dest.rz_Metafile		= src.rz_Metafile;
		dest.rz_Bodyfile		= src.rz_Bodyfile;
		dest.rz_Bodypath 		= src.rz_Bodypath;
		dest.rz_isPartPlay 		= src.rz_isPartPlay;
		dest.rz_PartPlayDuration= src.rz_PartPlayDuration;
		dest.rz_PartPlaySttp 	= src.rz_PartPlaySttp;
		dest.rz_PartPlayEndp 	= src.rz_PartPlayEndp;
		dest.rz_SoundDelay		= src.rz_SoundDelay;
		dest.rz_SeekAudioDelay	= src.rz_SeekAudioDelay;
		dest.rz_SeekAudioMagnify= src.rz_SeekAudioMagnify;
		dest.rz_MetaAspect		= src.rz_MetaAspect;
		dest.rz_MetaZoom		= src.rz_MetaZoom;
		dest.rz_MetaShift[0]	= src.rz_MetaShift[0];
		dest.rz_MetaShift[1]	= src.rz_MetaShift[1];
		dest.rz_MetaSoundVolume	= src.rz_MetaSoundVolume;
		dest.rz_MetaSoundSync	= src.rz_MetaSoundSync;
		dest.rz_MetaTransType	= src.rz_MetaTransType;
		dest.rz_MetaTransFormat	= src.rz_MetaTransFormat;
		dest.rz_MetaRemuxProc	= src.rz_MetaRemuxProc;
		dest.rz_MetaMencoderOpt	= src.rz_MetaMencoderOpt;
		dest.rz_MetaMencoderOptA= src.rz_MetaMencoderOptA;
		//dest.rz_WebOpt			= src.rz_WebOpt;
		dest.rz_MetaFFmpegOpt	= src.rz_MetaFFmpegOpt;
		dest.rz_MetaChannel_v	= src.rz_MetaChannel_v;
		dest.rz_MetaChannel_a	= src.rz_MetaChannel_a;
		dest.rz_MetaChannel_a_ffmpeg= src.rz_MetaChannel_a_ffmpeg;
		dest.rz_MetaDlnaProf	= src.rz_MetaDlnaProf;
		dest.rz_MetaDlnaOp		= src.rz_MetaDlnaOp;
		dest.rz_MetaMimeType	= src.rz_MetaMimeType;
		dest.rz_MetaDispDate	= src.rz_MetaDispDate;
		dest.rz_MetaSortType	= src.rz_MetaSortType;
		dest.rz_MetaTitle		= src.rz_MetaTitle;
		dest.rz_MetaDVDchapter	= src.rz_MetaDVDchapter;
		
		dest.wmed_duration	= src.wmed_duration;
	}

	public String getFolderCachePath() {	//regzamod add
		if(isFolder()) {
			return rz_Bodyfile.getAbsolutePath();
		}
		else {
			return null;
		}
	}
	
	public String getMediaCachePath (int[] rc) {	//regzamod add
		if(isDVDISO) {
			return this.dvdf.getMediaCachePath(rc);
		}
		rc[0]=0;
		if(!isFolder() && rz_Bodyfile!=null) {
			return rz_Bodyfile.getAbsolutePath();
		} else {
			return null;
		}
	}
	
	public void setResolved(boolean set) {	//regzamod add
		if(isDVDISO) {
			this.dvdf.setResolved(set);
			return;
		}
		//PMS.dbg("rz_PlayMetafile.setResolved: called, set="+set+", Meta="+getName()+", Body="+rz_Bodyfile);
		if(rz_Bodyfile!=null && rz_Bodyfile.isFile() && set==false) {
			//PMS.dbg("rz_PlayMetafile.setResolved: getMedia="+getMedia());
			if(getMedia()!= null) {
				/* partial init is not enoufgh
				//PMS.dbg("rz_PlayMetafile.setResolved: isMediaparsed()="+getMedia().isMediaparsed());
				if(getMedia().isMediaparsed()) {
					getMedia().setMediaparsed(false);
				}
				*/
				setMedia(new DLNAMediaInfo());  // whole re-create mediainfo
				resolved2=false;
				resolved=false;
			}
		} 
	}

	//--------------------------------------------------------------------------
	// implement DVDISOtitleIF
	//--------------------------------------------------------------------------
	//public abstract void resolve(); 
	
	@Override
	public long getLength() {
		if(isDVDISO) {
			return this.dvdf.getLength();
		}
		else {
			//return super.getLength();
			return 0;
		}
	}

	@Override
	//public InputStream getInputStream() throws IOException {
	public InputStream getInputStream() {
		if(isDVDISO) {
			try {
				return this.dvdf.getInputStream();
			} catch (IOException e) {
				return null;
			}
		}
		else {
			return super.getInputStream();
		}
	}

	@Override
	public void setName(String name) {
		sname=name;
		dname=name;
	}

	@Override
	public String getName() {
		//if(!resolved2) {
		if(!nameMnted) {
			//getName() may be called before resoved
			rz_isoNameMnt();
		}
		if(dname!=null) return dname;
		if(isDVDISO) {
			if(dvdf!=null) {
				return this.dvdf.getName();
			}
			else {
				return null;
			}
		}
		return sname;
	}
	
	/*
	@Override
	public String getDisplayName(RendererConfiguration mediaRenderer) {
		String name=super.getDisplayName(mediaRenderer);
		if(resname_pathadd_iso>=0) return;
		if(meta_type==2 && rz_Metafile2==null) { 		//resumeFile && target isn't Metafile-linked
			if(isDVDISO==true && sotype!=SO_DVDDEV) { 	//ISO file (not Real DVD)
				if(!isNoName() && dname2==null ) {  	//not under transcode folder 
					DLNAResource pa=getParent();
					if(pa!=null || !pa.isResumeFolderAll) {  //not under resume_all
						name=dvdf.getName0();
					}
				}
			}
		}
		return name;
	}
	*/

	public String getName0() {
		if(sname0!=null) {
			//name without metafile-specific indicator "(?)"
			return sname0;
		}
		else {
			return getName();
		}
	}
	
	@Override
	public String getDpName() {
		return getName();
	}
	
	@Override
	public String  getSrcPath() {	//regzamod
		return rz_Bodypath;
	}
	
	@Override
	public int  getTitleNum() {	//regzamod
		return dvd_title_num;
	}

	@Override
	public String getSystemName() {
		if(isDVDISO) {
			return this.dvdf.getSystemName();
		}
		else {
			return super.getSystemName();
		}
	}

	@Override
	public boolean allowScan() {
		//to avoid scan() cause scanning terrible many virtual folders 
		//that linked same few real folders
		return false;
	}

	@Override
	public boolean isFolder() {
		boolean rc=false;
		if(isDVDISO) {
			rc=this.dvdf.isFolder();
		}
		else if(isVfolder) {
			rc=true;
		}
		else {
			rc=isFolder_r();
		}
		//PMS.dbg("rz_PlayMetafile.isFolder called, isDVDISO="+isDVDISO+", return rc="+rc);
		return rc;
	}

	@Override
	public boolean isValid() {
		if(isDVDISO) {
			return this.dvdf.isValid();
		}
		else {
			return isValid_r();
		}
	}

	@Override
	public long length() {
		if(isDVDISO) {
			return this.dvdf.length();
		}
		else {
			return super.length();
		}
	}

	@Override
	public long length(RendererConfiguration mediaRenderer) {
		if(isDVDISO) {
			return DLNAMediaInfo.TRANS_SIZE;
			//return this.dvdf.length(mediaRenderer); //cause exception
		}
		else {
			return super.length(mediaRenderer);
		}
	}

	@Override
	public InputStream getThumbnailInputStream() throws IOException {
		if(isDVDISO) {
			return this.dvdf.getThumbnailInputStream();
		}
		else {
			return super.getThumbnailInputStream();
		}
	}
}

