package org.korsakow.domain.command;
import java.io.File;
import java.io.FileNotFoundException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.dsrg.soenea.domain.MapperException;
import org.dsrg.soenea.domain.command.CommandException;
import org.dsrg.soenea.environment.CreationException;
import org.dsrg.soenea.environment.KeyNotFoundException;
import org.dsrg.soenea.uow.UoW;
import org.korsakow.domain.Video;
import org.korsakow.domain.interf.IMedia;
import org.korsakow.domain.interf.IProject;
import org.korsakow.domain.mapper.input.ProjectInputMapper;
import org.korsakow.domain.mapper.input.VideoInputMapper;
import org.korsakow.ide.resources.ResourceType;
import org.korsakow.ide.util.MultiMap;
public class FindMissingFilesCommand extends AbstractCommand{
public FindMissingFilesCommand(Helper request, Helper response) {
super(request, response);
}
public void execute()
throws CommandException {
long projectId = request.getLong("id");
File basePath = new File(request.getString("basePath"));
boolean updateUniqueMatches = request.has("updateUniqueMatches")?request.getBoolean("updateUniqueMatches"):false;
IProject project;
try {
project = ProjectInputMapper.map(projectId);
} catch (MapperException e) {
throw new CommandException(e);
}
Collection<IMedia> media = project.getMedia();
Collection<IMedia> mediaMissingFiles = new HashSet<IMedia>();
MultiMap<String, File, Set<File>> filesToPossibleMatches = new MultiHashMapHashSet<String, File>();
// find media with missing files
for (IMedia medium : media)
{
File file = null;
try {
file = new File(medium.getAbsoluteFilename());
} catch (FileNotFoundException e) {
mediaMissingFiles.add(medium);
continue;
}
}
boolean modified = false;
Collection<String> uniqueMatches = new HashSet<String>();
Collection<IMedia> uniqueMatchedMedia = new HashSet<IMedia>();
// find possible matches to the missing files
for (IMedia medium : mediaMissingFiles)
{
File target = new File(medium.getFilename());
findFileRecursive(target, basePath, filesToPossibleMatches);
if (updateUniqueMatches) {
String name = target.getName();
if (filesToPossibleMatches.containsKey(name) && filesToPossibleMatches.size(name) == 1) {
File match = filesToPossibleMatches.get(name).iterator().next();
medium.setFilename(match.getAbsolutePath());
if ( ResourceType.VIDEO.isInstance( medium ) ) {
// map it because UnknownResourceProxy is a broken solution & we can't cast to IVideo
Video video;
try {
video = VideoInputMapper.map( medium.getId() );
} catch (MapperException e) {
throw new CommandException(e);
}
if ( video.getSubtitles() != null ) {
if ( match.getParent() != null ) {
File testFile = new File( match.getParent(), new File( video.getSubtitles() ).getName() );
if ( testFile.exists() && testFile.isFile() )
video.setSubtitles( testFile.getAbsolutePath() );
}
}
}
UoW.getCurrent().registerDirty(medium);
modified = true;
uniqueMatches.add(name);
uniqueMatchedMedia.add(medium);
}
}
}
filesToPossibleMatches.removeAll(uniqueMatches);
if (modified) {
try {
UoW.getCurrent().commit();
} catch (SQLException e) {
throw new CommandException(e);
} catch (KeyNotFoundException e) {
throw new CommandException(e);
} catch (CreationException e) {
throw new CommandException(e);
} catch (MapperException e) {
throw new CommandException(e);
}
}
if (updateUniqueMatches)
response.set("updatedMedia", uniqueMatchedMedia);
response.set("possibleMatches", filesToPossibleMatches);
}
public static void findFileRecursive(File target, File currentFile, MultiMap<String, File, Set<File>> filesToPossibleMatches)
{
if (currentFile.isDirectory()) {
File[] files = currentFile.listFiles();
if (files != null)
for (File child : files) {
findFileRecursive(target, child, filesToPossibleMatches);
}
} else {
if (currentFile.getName().equals(target.getName()))
filesToPossibleMatches.add(target.getName(), currentFile);
}
}
private static class MultiHashMapHashSet<KeyType, ValueType>
implements MultiMap<KeyType, ValueType, Set<ValueType>>
{
private final Map<KeyType, Set<ValueType>> map;
public MultiHashMapHashSet()
{
this.map = new HashMap<KeyType, Set<ValueType>>();
}
private Set<ValueType> ensure(KeyType key)
{
Set<ValueType> values = map.get(key);
if (values == null) {
values = new HashSet<ValueType>();
map.put(key, values);
}
return values;
}
public void add(KeyType key, ValueType value)
{
ensure(key).add(value);
}
public Set<ValueType> get(KeyType key) {
return map.get(key);
}
public boolean containsKey(KeyType key) {
return map.containsKey(key);
}
public int size()
{
return map.size();
}
public int size(KeyType key)
{
return ensure(key).size();
}
public boolean isEmpty()
{
return map.isEmpty();
}
public boolean isEmpty(KeyType key)
{
Set<ValueType> values = map.get(key);
if (values == null)
return true;
return values.isEmpty();
}
public boolean removeAll(Collection<KeyType> keys)
{
boolean modified = false;
for (KeyType key : keys) {
modified = modified || map.containsKey(key);
map.remove(key);
}
return modified;
}
}
}