/*
 * PS3 Media Server, for streaming any medias to your PS3.
 * Copyright (C) 2008  A.Brochard
 *
 * 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.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import com.sun.jna.Platform;	//regzamod
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.pms.PMS;
import net.pms.formats.Format;
import net.pms.util.FileUtil;
import net.pms.util.ProcessUtil;
import net.pms.util.PMSUtil;	//regzamod
import net.pms.encoders.Player;


public class RealFile extends MapFile {
	private static final Logger logger = LoggerFactory.getLogger(RealFile.class);
	//private int onBDMV;

	public RealFile() {	//regzamod, for subclass rz_PlayMetafile construct
	  	//noop
	}
	
	public RealFile(File file) {
		RealFile_in(file,null);
		//PMS.dbg("RealFile constructor: name="+"null"+", getFile().getName()="+getFile().getName());
	}

	public RealFile(File file, String name) {
		RealFile_in(file,name);
	}
	
	private void RealFile_in(File file, String name) {
		getConf().getFiles().add(file);
		if(name!=null) getConf().setName(name);
		setLastmodified(file.lastModified());
		/* will be done by MapFile.ananyzeChildren
		File pxf;
		pxf=new File(getSrcPath()+"."+PMS.rz_ProfileSuffix);
		if(pxf.exists()) {
			rz_PlayMetaFile.pxf_read(this,pxf);
		}
		if(PMS.rz_ProfileEnabled>1 && isFolder()) {
			// check if pxf exists under me
		 	pxf=new File(getSrcPath()+PMS.FSEP+PMS.rz_ProfileFF);
		 	if(pxf.exists()) {
				rz_PlayMetaFile.pxf_read(this,pxf);
		 	}
		}
		*/		
		//PMS.dbg("RealFile constructor: name="+name+", getFile().getName()="+getFile().getName());
	}

	private boolean fexists(File f) { //regzamod for speed test
		if((PMS.rz_update_check_nls&0x4)==0) {
			return true;
		}
		else {
			return f.exists();
		}
	}
	
	@Override
	public boolean needRealFileMatching() {
		return true;
	}
	
	@Override
	// FIXME: this is called repeatedly for invalid files e.g. files MediaInfo can't parse
	// and this is some heavy proc!!
	public boolean isValid () {
		
		if(PMS.rz_debug>2) PMS.dbg("==== RealFile.isValid pos-1: isOnSlowMedia()="+isOnSlowMedia()+", name="+getName());

		File file = this.getFile();
		if(file==null) {
			if(PMS.rz_debug>2) PMS.dbg("==== RealFile.isValid pos-1b: file==null, return false, name="+getName());
			return false;
		}
		
		if(PMS.rz_debug>2) PMS.dbg("==== RealFile.isValid pos-2: name="+getName()+", getFile="+file);
		if(Platform.isWindows() && file.getPath().matches("[A-Z]:.")) {	//regzamod test
			if(PMS.rz_debug>1) PMS.dbg1("RealFile.isValid: file seems to be RemovableDrive, path="+file.getPath());
			if(isRemovableDrive) { 
				return true;
			}
			isRemovableDrive=true;
			return true;
		}
		
		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.isValid pos-3: name="+getName());
		checktype();
		
		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.isValid pos-4: name="+getName());
		//Caution: File.exisis() is heavy expensive (on WindowsOS only?)
		//if (getType() == Format.VIDEO && file.exists() && PMS.getConfiguration().getUseSubtitles() && file.getName().length() > 4) {
		
			
		if (false && getType() == Format.VIDEO && fexists(file) && PMS.getConfiguration().getUseSubtitles() && file.getName().length() > 4) {
			if(true) {
				if(!isOnSlowMedia()) {
					setSrtFile(FileUtil.doesSubtitlesExists(file, null));
				}
			}
			else {
				setSrtFile(FileUtil.doesSubtitlesExists(file, null));
			}
		}
		
		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.isValid pos-5: name="+getName());
		//Caution: File.exisis() is heavy expensive (on windowsOS only?)
		//boolean valid = file.exists() && (getExt() != null || file.isDirectory());
		boolean valid = fexists(file) && (getExt() != null || file.isDirectory());

		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.isValid pos-6: name="+getName());
		if (!PMS.isMediaCacheClearRunning && valid && getParent().getDefaultRenderer() != null 
			&& getParent().getDefaultRenderer().isMediaParserV2()) {
			// we need to resolve the dlna resource now
			if(PMS.rz_debug>1) PMS.dbg("==== RealFile.isValid pos-6b: name="+getName()+", isMediaParserV2=true: exec resolve now");
			run();
			if (getMedia() != null && getMedia().getThumb() == null && getType() != Format.AUDIO) // MediaInfo retrieves cover art now
			{
				getMedia().setThumbready(false);
			}
			if (getMedia() != null && (getMedia().isEncrypted() || getMedia().getContainer() == null || getMedia().getContainer().equals(DLNAMediaLang.UND))) {
				// fine tuning: bad parsing = no file !
				valid = false;
				if (getMedia().isEncrypted()) {
					logger.info("The file " + file.getAbsolutePath() + " is encrypted. It will be hidden");
				} else {
					logger.info("The file " + file.getAbsolutePath() + " was badly parsed. It will be hidden");
				}
			}
			if (getParent().getDefaultRenderer().isMediaParserV2ThumbnailGeneration()
				&& PMS.getConfiguration().getRZ_thumbnails_getlater()==0) {
				checkThumbnail();
			}
		}
		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.isValid pos-7: name="+getName());
		return valid;
	}

	@Override
	public InputStream getInputStream() {
		try {
			return new FileInputStream(getFile());
		} catch (FileNotFoundException e) {
		}
		return null;
	}

	@Override
	public long length() {
		if (getPlayer() != null && getPlayer().type() != Format.IMAGE) {
			return DLNAMediaInfo.TRANS_SIZE;
		} else if (getMedia() != null && getMedia().isMediaparsed()) {
			return getMedia().getSize();
		}
		return getFile().length();
	}
	@Override
	public boolean isRealFile() {
		return true;
	}

	@Override
	public boolean isFolder() {
		if(isRemovableDrive) return true;	//regzamod
		return getFile().isDirectory();
	}
	

	@Override
	public File getFile () {
		try {
			return getConf().getFiles().get(0);
		}
		catch (IndexOutOfBoundsException e) {
			logger.error("RealFile.getFile: IndexOutOfBoundsException, name="+getName()
				+", getConf()="+getConf()
				+", getFiles()="+(getConf()==null?"null":getConf().getFiles()));
			return null;
		}
	}

	public String getFolderCachePath() {	//regzamod add
		if(isFolder()) {
			return getFile().getAbsolutePath();
		}
		else {
			return null;
		}
	}
	
	public String getMediaCachePath (int[] rc) {	//regzamod add
		rc[0]=0;
		if(isFolder()) {
			return null;
		}
		else {
			return getFile().getAbsolutePath();
		}
	}
	
	public void setResolved(boolean set) {	//regzamod add
		if(getFile().isFile()) {
			if(set==false) {
				if(getMedia() != null) {
					setMedia(new DLNAMediaInfo());  //clear mediainfo
					resolved=false;
					if(PMS.rz_debug>1) PMS.dbg("RealFile.setResolved: name="+getName()+", cleared MediaInfo, isMediaparsed="+getMedia().isMediaparsed());
					isValid();  //for resolve now, if isMediaParserV2
					//FileUtil.ClearSubtitlesCache();
				}
				else {
					if(PMS.rz_debug>1) PMS.dbg("RealFile.setResolved: name="+getName()+", getMedia()==null: Noop");
				}
			}
			else {
				//set true OK?
			}
			/*
			if(getMedia() != null && getMedia().isMediaparsed()) {
				getMedia().setMediaparsed(false);
				resolved=false;
			}
			*/
		}
		else {
			// may be folder
		}
		resolved=set;
	}

	private boolean delayedClear;
	public void setDelayedClear(boolean set) {	//regzamod
		delayedClear=set;
	}
	public boolean getDelayedClear() {	//regzamod
		return delayedClear;
	}
	
	public String  getSrcPath () {	//regzamod
		return getFile().getAbsolutePath();
	}
	public File getBodysParentFolder() {
		if(getFile()==null) return null;
		return getFile().getParentFile();
	}
		
	@Override
	public String getDpName () {	//regzamod
		if(getForcedTitle()!=null) {
			return getForcedTitle();
		}
		if(is_aav()) { //cause folder/file confusion on REGZA
			DLNAMediaAudio firstAudioTrack = getMedia() != null ? getMedia().getFirstAudioTrack() : null;
			if(firstAudioTrack != null && StringUtils.isNotBlank(firstAudioTrack.getSongname())) {
				String artist=firstAudioTrack.getArtist();
				if(artist!=null && artist.length()>0) artist=artist+" - ";
				else artist="";
				return artist+firstAudioTrack.getSongname();
			}
		}
		return getName();
	}
		
	@Override
	public String getName () {
		if(dname!=null) {
			return dname;
		}
		if (this.getConf().getName() == null ||updateDiskLabel) {
			String name = null;
			File file = getFile();
			if(file.getName().trim().equals("") ||updateDiskLabel) { //regzamod TEST!!
				//for rootDirs e.x. RemovableStorages(DVD,USB etc)
				if (PMS.get().isWindows()) {
					//PMS.dbg("getDiskLabel start ");
					//name="Unknown DiskLabel for Test";	//regzamod test
					name = PMS.get().getRegistry().getDiskLabel(file);
					//PMS.dbg("getDiskLabel: label="+name);
				}
				if (name != null && name.length() > 0) {
					name = file.getAbsolutePath().substring(0, 1) + ":\\ [" + name + "]";
				} else {
					name = file.getAbsolutePath().substring(0, 1);
				}
				//regzamod, don't getConf().setName(name)
				//if done, next DiskLabel update will not occur
				//because getConf().getName() != null
				//return name;	//add, regzamod	
			} else {
				name = file.getName();
			}
			this.getConf().setName(name);
			updateDiskLabel=false;
		}
		return this.getConf().getName();
	}	
		
	@Override
	public String getName0 () {//real file name
		//String name=getFile().getName();
		//return name==null?getName():name;
		return getFile().getName();
	}

	@Override
	protected void checktype() {
		if (getExt() == null) {
			setExt(PMS.get().getAssociatedExtension(getFile().getAbsolutePath()));
		}
		super.checktype();
	}

	@Override
	public String getSystemName () {
		if(getFile()==null) return null;
		return ProcessUtil.getShortFileNameIfWideChars(getFile().getAbsolutePath());
	}
	
	//---- isRefreshNeeded func for file (that Already Resolved)
	@Override
	public boolean needReCreate() {	//regzamod add
		//if need change on subclasses, override me
		
		if(PMS.rz_debug>1) PMS.dbg("RealFile.needReCreate: Start, file="+getSrcPath());
		//PMS.dbg("RealFile.needReCreate: caled, name="+getName()+", rz_Profile="+rz_Profile);
		if(false && !resolved) {
			//--> Noop: "checking resolved" is out of duty
			//PMS.dbg("RealFile.needReCreate: caled, Not Resolved --> return true, name="+getName()+", rz_Profile="+rz_Profile);
			if(PMS.rz_debug>1) PMS.dbg("RealFile.needReCreate: End-1(not-resolved yet) rc=true");
			return true;
		}
		if(!isFolder() && (PMS.rz_update_check_nls&0x2)!=0) {  //check modified
			File file = getFile();
			if(file!=null) {
				if(getLastmodified() < file.lastModified()) {
					if(PMS.rz_debug>1) {
						PMS.dbg("RealFile.needReCreate: End-2(file updated) rc=true"
							+", file.lastModified()="+PMSUtil.convTime2Date(file.lastModified())
							+", getLastmodified()="  +PMSUtil.convTime2Date(getLastmodified())
						);
					}
					return true;
				}
			}
		}
		
		if(rz_Profile!=null) {
			//in this case, purpose is only resolve pxf, not mediabody it's self
			//re-create body is too heavy load, for the purpose, should be refined.
			boolean b=pxf_lastmodified != rz_Profile.lastModified();
			//PMS.dbg("RealFile.needReCreate: return "+b+", name="+getName());
			if(PMS.rz_debug>1) PMS.dbg("RealFile.needReCreate: End-3(profile updated) ,rc="+b);
			return (b);
		}
		//PMS.dbg("RealFile.needReCreate: return FALSE, name="+getName());
		if(PMS.rz_debug>1) PMS.dbg("RealFile.needReCreate: End-4(no-need update) ,rc=false");
		return false;
	}

	@Override
	public void resolve () {
		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.resolve: Start, name="+getName());
		boolean found = true;
		if(resolved) {
			if(PMS.rz_debug>1) PMS.dbg("==== RealFile.resolve: End, Already resolved, name="+getName());
			return;
		}
		
		File file = getFile();
		if(file==null) {
			if(PMS.rz_debug>1) PMS.dbg("==== RealFile.resolve: End, file==null, name="+getName());
			return;
		}
		toString_sb=null;  //clear cache of toString()
		boolean isFile=file.isFile();
		InputFile input = new InputFile();
		input.setFile(file);

		//--- media parse
		//Caution: File.exisis() is heavy expensive (on WindowsOS only?)
		//if (file.isFile() && file.exists() && (getMedia() == null || !getMedia().isMediaparsed())) {
		if (isFile && fexists(file) && (getMedia() == null || !getMedia().isMediaparsed())) {
			found = false;
			//InputFile input = new InputFile();
			//input.setFile(file);
			String fileName = file.getAbsolutePath();
			//PMS.dbg("RealFile.resolve: filePath="+fileName);
			
			if (getSplitTrack() > 0) {
				fileName += "#SplitTrack" + getSplitTrack();
			}
			
			if (PMS.getConfiguration().getUseCache()) {
				if(PMS.rz_debug>1) PMS.dbg("RealFile: get MediaDB Start , filePath="+fileName);
				
				DLNAMediaDatabase database = PMS.get().getDatabase();
				if (database != null) {
					ArrayList<DLNAMediaInfo> medias = database.getData(fileName, file.lastModified());

					//if (medias != null && medias.size() == 1) {
					if (medias != null && medias.size() >= 1) {
						setMedia(medias.get(0));
						if(getExt()!=null && getExt().isVideo() && getMedia().getWidth()<=0) {
							//may be failed before --> treat as not found
							database.delData(fileName,1); // once delete 
							logger.warn("RealFile.resolve: media insane -> retry parse media, file="+file.getAbsolutePath());
							logger.warn("RealFile.resolve: media aspect="+getMedia().getAspect_f()+",width="+getMedia().getWidth());
						}
						else {
							getMedia().finalize(getType(), input, this);
							found = true;
							if(medias.size() >= 2) {
								logger.warn("RealFile.resolve: data duplicated! correct dup-count="+medias.size()+", fileName="+fileName);
								database.delData(fileName,1); // once delete 
								database.insertData(fileName, file.lastModified(), getType(), getMedia());
								//why happen this? should delete duplicateds
							}
						}
					}
					else {
						//PMS.dbg("RealFile.resolve: database.getData failed, medias="+medias+", fileName="+fileName);
					}
				}
				if(PMS.rz_debug>1) PMS.dbg("RealFile: get MediaDB End , found="+found+", filePath="+fileName);
			}

			if (!found) {
				//PMS.dbg("RealFile.resolve: first getMedia()= "+getMedia());
				if (getMedia() == null) {
					setMedia(new DLNAMediaInfo());
				}
				getMedia().setMediaparsed(false);
				//found = !getMedia().isMediaparsed() && !getMedia().isParsing(); //origin, why here?
				if (getExt() != null) {
					//FormatConfiguration.parse()
					if(PMS.rz_debug>1) {
						PMS.dbg("RealFile.resolve: call getExt().parse, getExt() != null, getType()="
						+getType()+"(IMAGE="+Format.IMAGE+",VIDEO="+Format.VIDEO+")");
					}
					getExt().parse(getMedia(), input, getType(), getParent().getDefaultRenderer(),this);
					
					if(false) { //moved later
						// you must change whole data concering to previous setExt()
						if(getMedia().getCodecV()!=null && getExt().getType()==Format.AUDIO) {
							if(PMS.rz_debug>1) {
								PMS.dbg("RealFile.resolve: name="+getName()+", judged getType()="+getExt().getType()
									+" isn't VIDEO, but has codecV --> force getType()="+Format.VIDEO+" (VIDEO)");
							}
							//force media type=VIDEO, and re-finalize
							setExt(PMS.get().getAssociatedExtension("xx.mp4"));
							getMedia().finalize(getExt().getType(),input,this);
						}
						else if(getMedia().getCodecV()==null && getExt().getType()==Format.VIDEO) {
							if(PMS.rz_debug>1) {
								PMS.dbg("RealFile.resolve: name="+getName()+", judged getType()="+getExt().getType()
									+" is VIDEO, but hasn't codecV --> force getType()="+Format.AUDIO+" (AUDIO)");
							}
							//force media type=AUDIO, and re-finalize
							setExt(PMS.get().getAssociatedExtension("xx.mp3"));
							getMedia().finalize(getExt().getType(), input,this);
							
							// change player for aav (original player is judged by addChild, according to only file suffix, before resolve)
							boolean is_aav=(getSession()==null?false:getSession().is_aav);
							if(is_aav) {
								Player pl=PMS.get().getPlayer("rz_audio_as_video_tc");
								setPlayer(pl);
							}
							else {
								//tobe setted!
							}
							if(PMS.rz_debug>1) {
								PMS.dbg("RealFile.resolve: is VIDEO, but hasn't codecV --> force AUDIO, getType="+getExt().getType()
									+", player="+getPlayer());
							}
						}
						else {
							//finalize is already done by getExt().parse() it'self
						}
					}
				} 
				else {	//don't think that will ever happen
					//DLNAMediainfo.parse()
					//PMS.dbg("RealFile.resolve: getExt() == null, exec getMedia().parse");
					getMedia().parse(input, getExt(), getType(), false,this);
				}
				found = getMedia().isMediaparsed() && !getMedia().isParsing();// regzamod, moved to here
				if(PMS.rz_debug>=5) {
					PMS.dbg("RealFile.resolve: found="+found
						+", getMedia().isMediaparsed()= "+getMedia().isMediaparsed()
						+", getMedia().isParsing= "+getMedia().isParsing());
				}

				if (found && PMS.getConfiguration().getUseCache()) {
					if(PMS.rz_debug>1) PMS.dbg("RealFile: Insert MediaDB Start, filePath="+fileName);

					DLNAMediaDatabase database = PMS.get().getDatabase();
					if (database != null) {
						if(getMedia().getWidth()<=0) {
							getMedia().setWidth(1);	//dummy set indicate parse succeeded 
						}
						
						database.insertData(fileName, file.lastModified(), getType(), getMedia());
					}
					if(PMS.rz_debug>1) PMS.dbg("RealFile: Insert MediaDB End, filePath="+fileName);
				}
			}
		}
		
		//re-judge mediaType for spacial cases
		if(getMedia()!=null && getExt()!=null) { //moved here
			// you must change whole data concering to previous setExt()
			if(getMedia().getCodecV()!=null && getExt().getType()==Format.AUDIO) {
				if(PMS.rz_debug>1) {
					PMS.dbg("RealFile.resolve: name="+getName()+", judged getType()="+getExt().getType()
						+" isn't VIDEO, but has codecV --> force getType()="+Format.VIDEO+" (VIDEO)");
				}
				//force media type=VIDEO, and re-finalize
				setExt(PMS.get().getAssociatedExtension("xx.mp4"));
				getMedia().finalize(getExt().getType(),input,this);
			}
			else if(getMedia().getCodecV()==null && getExt().getType()==Format.VIDEO) {
				if(PMS.rz_debug>1) {
					PMS.dbg("RealFile.resolve: name="+getName()+", judged getType()="+getExt().getType()
						+" is VIDEO, but hasn't codecV --> force getType()="+Format.AUDIO+" (AUDIO)");
				}
				//force media type=AUDIO, and re-finalize
				setExt(PMS.get().getAssociatedExtension("xx.mp3"));
				getMedia().finalize(getExt().getType(), input,this);
				
				// change player for aav (original player is judged by addChild, according to only file suffix, before resolve)
				boolean is_aav=(getSession()==null?false:getSession().is_aav);
				if(is_aav) {
					Player pl=PMS.get().getPlayer("rz_audio_as_video_tc");
					setPlayer(pl);
				}
				if(PMS.rz_debug>0) PMS.dbg("RealFile.resolve: file format is VIDEO, but hasn't codecV --> force AUDIO"
					+", getType="+getExt().getType()
					+", player="+getPlayer()
					+", file="+getSrcPath());
			}
			else {
				//finalize is already done by getExt().parse() it'self
			}
		}

		//---- for PlayProfile
		//if(rz_Profile!=null) {
		if(isFile && meta_type!=1) {  //meta_type==1: playMetafile 
			//body changed, need force resolve pxf
			//pxf_resolved=false;
			//PMS.dbg("RealFile.resolve: exec pxf_resolve");
			rz_PlayMetaFile.pxf_resolve(this,0);
		}

		//regzamod, special suffix for force trans_type
		//public int rz_MetaTransType={ENC_DIRECT|ENC_REMUX|ENC_TRANSCODE|-1}, -1:not setted 
		if(file.getName().endsWith("_d")) {
			//PMS.dbg("RealFile.resolve: suffix_d: set rz_MetaTransType=ENC_DIRECT");
			rz_MetaTransType[0]=PMS.ENC_DIRECT;
		}
		else if(file.getName().endsWith("_r")) {
			//PMS.dbg("RealFile.resolve: suffix_r: set rz_MetaTransType=ENC_REMUX");
			rz_MetaTransType[0]=PMS.ENC_REMUX;
		}
		else if(file.getName().endsWith("_t")) {
			//PMS.dbg("RealFile.resolve: suffix_t: set rz_MetaTransType=ENC_TRANSCODE");
			rz_MetaTransType[0]=PMS.ENC_TRANSCODE;
		}
		else if(file.getName().endsWith(".avs")) {
			//PMS.dbg("RealFile.resolve: avs file --> force format to mpegps");
			rz_MetaTransFormat[0]=PMS.TRS_MPEGPS;	// avs don't work well on m2ts(mencoder*2+tsMuxer)
		}
		//params in filename
		//resolve_fparam(file);  //deprecated
		//super.resolve();
		if(found) {
			//setLastmodified(System.currentTimeMillis());
			resolved=true;
		}
		else if(!resolved) {
			logger.warn("RealFile.resolve: failed, may be timeouted: try later, file="+getSrcPath()+", media="+getMedia());
		}
		if(PMS.rz_debug>1) PMS.dbg("==== RealFile.resolve: End, normally, name="+getName());

	}
	
	public void resolve_fparam(File file) {
		
		//params in filename
		String[] fparams=PMSUtil.rz_getFnameParams(file.getName());
		double sttp=0,endp=0;
		if(fparams[0]!=null) {	//sound delay in secs
			rz_SoundDelay[0]=Double.parseDouble(fparams[0]);
			//PMS.dbg("RealFile.resolve: rz_SoundDelay="+rz_SoundDelay[0]);
		}
		if(fparams[1]!=null) {	//part play start time
			sttp=Double.parseDouble(fparams[1]);
		}
		if(fparams[2]!=null) {	//part play end time
			endp=Double.parseDouble(fparams[2]);
		}
		if(sttp!=0 || endp!=0) {  //range setted
			//PMS.dbg("RealFile.resolve: part_play start_pos="+sttp+", end_pos="+endp);
			if(sttp<0) {
				sttp=0;
			}
			if(endp<=0) {
				if(getMedia()!=null) {
					endp=getMedia().getDurationInSeconds();
				}
				else {
					logger.warn("resolve_param: can't get media duration, file="+file);
					endp=1800d;
				}
			}
			setSplitRange(new Range.Time(sttp,endp));
			rz_isPartPlay=true;
			rz_PartPlaySttp=sttp;
			rz_PartPlayEndp=endp;
			rz_PartPlayDuration=endp - sttp;
		}
		//--- regzamod end
	}

	@Override
	public String getThumbnailContentType() {
		return super.getThumbnailContentType();
	}

	@Override
	public InputStream getThumbnailInputStream() throws IOException {
		File file = getFile();
		File cachedThumbnail = null;
		if (getParent() != null && getParent() instanceof RealFile) {
			cachedThumbnail = ((RealFile) getParent()).getPotentialCover();
			File thumbFolder = null;
			boolean alternativeCheck = false;
			while (cachedThumbnail == null) {
				if (thumbFolder == null && getType() != Format.IMAGE) {
					thumbFolder = file.getParentFile();
				}
				cachedThumbnail = FileUtil.getFileNameWitNewExtension(thumbFolder, file, "jpg");
				if (cachedThumbnail == null) {
					cachedThumbnail = FileUtil.getFileNameWitNewExtension(thumbFolder, file, "png");
				}
				if (cachedThumbnail == null) {
					cachedThumbnail = FileUtil.getFileNameWitAddedExtension(thumbFolder, file, ".cover.jpg");
				}
				if (cachedThumbnail == null) {
					cachedThumbnail = FileUtil.getFileNameWitAddedExtension(thumbFolder, file, ".cover.png");
				}
				if (alternativeCheck) {
					break;
				}
				if (StringUtils.isNotBlank(PMS.getConfiguration().getAlternateThumbFolder())) {
					thumbFolder = new File(PMS.getConfiguration().getAlternateThumbFolder());
					if (!thumbFolder.exists() || !thumbFolder.isDirectory()) {
						thumbFolder = null;
						break;
					}
				}
				alternativeCheck = true;
			}
			if (file.isDirectory()) {
				cachedThumbnail = FileUtil.getFileNameWitNewExtension(file.getParentFile(), file, "/folder.jpg");
				if (cachedThumbnail == null) {
					cachedThumbnail = FileUtil.getFileNameWitNewExtension(file.getParentFile(), file, "/folder.png");
				}
			}

		}
		boolean hasAlreadyEmbeddedCoverArt = getType() == Format.AUDIO && getMedia() != null && getMedia().getThumb() != null;
		if (cachedThumbnail != null && (!hasAlreadyEmbeddedCoverArt || file.isDirectory())) {
			return new FileInputStream(cachedThumbnail);
		} else if (getMedia() != null && getMedia().getThumb() != null) {
			return getMedia().getThumbnailInputStream();
		} else {
			return super.getThumbnailInputStream();
		}
	}

	@Override
	public void checkThumbnail() {
		InputFile input = new InputFile();
		input.setFile(getFile());
		checkThumbnail(input);
	}

	@Override
	protected String getThumbnailURL() {
		if (getType() == Format.IMAGE && !PMS.getConfiguration().getImageThumbnailsEnabled())
		{
			return null;
		}
		StringBuilder sb = new StringBuilder();
		sb.append(PMS.get().getServer().getURL());
		sb.append("/");
		if (getMedia() != null && getMedia().getThumb() != null) {
			return super.getThumbnailURL();
		} else if (getType() == Format.AUDIO) {
			if (getParent() != null && getParent() instanceof RealFile && ((RealFile) getParent()).getPotentialCover() != null) {
				return super.getThumbnailURL();
			}
			return null;
		}
		return super.getThumbnailURL();
	}
}
