package managers;

import models.Account;
import models.Folder;
import models.Media;
import models.enums.GroupType;
import models.enums.LinkType;
import models.services.ElasticsearchService;
import play.Configuration;
import play.Logger;
import play.db.jpa.JPAApi;

import java.io.IOException;
import java.nio.file.Files;

import javax.inject.Inject;
import java.io.File;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Iven on 17.12.2015.
 */
public class MediaManager implements BaseManager {

    final Logger.ALogger LOG = Logger.of(MediaManager.class);

    @Inject
    NotificationManager notificationManager;

    @Inject
    Configuration configuration;

    @Inject
    GroupAccountManager groupAccountManager;

    @Inject
    FriendshipManager friendshipManager;

    @Inject
    ElasticsearchService elasticsearchService;

    @Inject
    JPAApi jpaApi;

    final String tempPrefix = "htwplus_temp";

    @Override
    public void create(Object model) {
        Media media = (Media) model;
        media.size = media.file.length();
        media.url = createRelativeURL() + "/" + getUniqueFileName(media.fileName);
        try {
            createFile(media);
            jpaApi.em().persist(media);
            elasticsearchService.index(media);
        } catch (Exception e) {
            try {
                throw e;
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    }

    @Override
    public void update(Object model) {
        jpaApi.em().merge(model);
    }

    @Override
    public void delete(Object model) {
        Media media = (Media) model;

        try {
            // remove deprecated notifications
            notificationManager.deleteReferences(media);

            deleteFile(media);
            jpaApi.em().remove(media);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    public List<Media> findAll() {
        return jpaApi.em().createQuery("FROM Media").getResultList();
    }

    public Media findById(Long id) {
        Media media = jpaApi.em().find(Media.class, id);
        return media;
    }

    @SuppressWarnings("unchecked")
    public List<Media> findByFolder(Long folderId) {
        List<Media> mediaList = jpaApi.em().createQuery("FROM Media m WHERE m.folder.id = " + folderId).getResultList();
        List<Media> returningMediaList = new ArrayList<>();
        for (Media media : mediaList) {
            String path = configuration.getString("media.path");
            media.file = new File(path + "/" + media.url);
            if (media.file.exists()) {
                returningMediaList.add(media);
            }
        }
        return returningMediaList;
    }

    @SuppressWarnings("unchecked")
    public List<Media> listAllOwnedBy(Long id) {
        return jpaApi.em().createQuery("FROM Media m WHERE m.owner.id = " + id).getResultList();
    }

    public boolean existsInFolder(String mediaTitle, Folder folder) {
        List<Media> mediaList = findByFolder(folder.id);
        for (Media media : mediaList) {
            if (media.title.equals(mediaTitle)) {
                return true;
            }
        }
        return false;
    }


    public boolean isOwner(Long mediaId, Account account) {
        Media m = jpaApi.em().find(Media.class, mediaId);
        if (m.owner.equals(account)) {
            return true;
        } else {
            return false;
        }
    }

    private String getUniqueFileName(String fileName) {
        return UUID.randomUUID().toString() + '_' + fileName;
    }

    private void deleteFile(Media media) throws FileNotFoundException {
        String path = configuration.getString("media.path");
        File file = new File(path + "/" + media.url);
        if (file.exists()) {
            file.delete();
        } else {
            throw new FileNotFoundException("File does not exist.");
        }
    }

    private void createFile(Media media) throws Exception {
        String path = configuration.getString("media.path");
        File newFile = new File(path + "/" + media.url);
        if (newFile.exists()) {
            throw new Exception("File exists already");
        }
        newFile.getParentFile().mkdirs();
        Files.move(media.file.toPath(), newFile.toPath());
        if (!newFile.exists()) {
            throw new Exception("Could not upload file");
        }
    }

    private String createRelativeURL() {
        Date now = new Date();
        String format = new SimpleDateFormat("yyyy/MM/dd").format(now);
        return format;
    }

    public String bytesToString(long bytes, boolean si) {
        int unit = si ? 1000 : 1024;
        if (bytes < unit) return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(unit));
        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
        return String.format("%.2f %sB", bytes / Math.pow(unit, exp), pre);
    }

    /**
     * Cleans the temporary media directoy used for ZIP Downloads
     */
    public void cleanUpTemp() {
        LOG.info("Cleaning the Tempory Media Directory");

        String tmpPath = configuration.getString("media.tempPath");
        File dir = new File(tmpPath);
        LOG.debug("Directory: " + dir.toString());
        File[] files = dir.listFiles();
        LOG.debug("Absolut Path: " + dir.getAbsolutePath());

        if (files != null) {
            // Just delete files older than 1 hour
            long hours = 1;
            long eligibleForDeletion = System.currentTimeMillis() - (hours * 60 * 60 * 1000L);

            LOG.info("Found " + files.length + " Files");
            if (files != null) {
                for (File file : files) {
                    LOG.info("Working on " + file.getName());
                    if (file.getName().startsWith(tempPrefix) && file.lastModified() < eligibleForDeletion) {
                        LOG.info("Deleting: " + file.getName());
                        file.delete();
                    }
                }
            }
        } else {
            LOG.info("files is null");
        }

    }

    public int byteAsMB(long size) {
        return (int) (size / 1024 / 1024);
    }

    public long indexAllMedia() throws IOException {
        final long start = System.currentTimeMillis();
        for (Media medium : findAll()) elasticsearchService.index(medium);
        return (System.currentTimeMillis() - start) / 1000;

    }

    /**
     * Collect all AccountIds, which are able to view this medium
     *
     * @return List of AccountIds
     */
    public Set<Long> findAllowedToViewAccountIds(Media medium) {

        Set<Long> viewableIds = new HashSet<>();

        Folder rootFolder = medium.findRoot();

        // medium belongs to account
        if (rootFolder.account != null) {
            // owner is allowed
            viewableIds.add(rootFolder.owner.id);
            // friends is allowed
            viewableIds.addAll(friendshipManager.findFriendsId(rootFolder.owner));
        }

        // medium belongs to group
        if(rootFolder.group != null) {
            viewableIds.addAll(groupAccountManager.findAccountIdsByGroup(rootFolder.group, LinkType.establish));
        }

        return viewableIds;
    }

    public boolean isPublic(Media medium) {
        if(medium.findGroup() != null) {
            return medium.findGroup().groupType.equals(GroupType.open);
        }
        return false;
    }
}

@@ -2271,21 +2271,292 @@
     
-return media;
+if (media == null) %7B%0A            return null;%0A        %7D%0A        String path = configuration.getString(%22media.path%22);%0A        media.file = new File(path + %22/%22 + media.url);%0A        if (media.file.exists()) %7B%0A            return media;%0A        %7D else %7B%0A            return null;%0A        %7D
 %0A   

Fix MediaManager