// Copyright 2015 Eivind Vegsundvåg
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ninja.eivind.hotsreplayuploader.repositories;

import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.spring.DaoFactory;
import com.j256.ormlite.stmt.DeleteBuilder;
import com.j256.ormlite.stmt.PreparedDelete;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.SelectArg;
import com.j256.ormlite.support.ConnectionSource;
import ninja.eivind.hotsreplayuploader.di.Initializable;
import ninja.eivind.hotsreplayuploader.files.AccountDirectoryWatcher;
import ninja.eivind.hotsreplayuploader.models.ReplayFile;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Implementation of a {@link FileRepository}, which is based on a database backend.<br>
 * Uses ORMLite to abstract database access.
 */
@Singleton
public class OrmLiteFileRepository implements FileRepository, Initializable, Closeable {

    @Inject
    private ConnectionSource connectionSource;
    private Dao<ReplayFile, Long> dao;
    @Inject
    private AccountDirectoryWatcher accountDirectoryWatcher;

    /**
     * Initializes this object after all members have been injected. Called automatically by the IoC context.
     */
    @Override
    public void initialize() {
        try {
            dao = DaoFactory.createDao(connectionSource, ReplayFile.class);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteReplay(final ReplayFile replayFile) {
        try {
            dao.delete(replayFile);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void updateReplay(final ReplayFile file) {
        try {
            dao.createOrUpdate(file);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<ReplayFile> getAll() {
        List<String> fileNames = accountDirectoryWatcher.getAllFiles()
                .map(ReplayFile::fromDirectory)
                .flatMap(List::stream)
                .map(ReplayFile::getFileName).collect(Collectors.toList());

        return getAllByFileNames(fileNames)
                .map(replayFile -> {
                    File file = replayFile.getFile();
                    if (file.exists()) {
                        return replayFile;
                    } else {
                        try {
                            dao.delete(replayFile);
                            return null;
                        } catch (SQLException e) {
                            throw new RuntimeException(e);
                        }
                    }
                })
                .collect(Collectors.toList());
    }

    @Override
    public void deleteByFileName(ReplayFile file) {
        SelectArg selectArg = new SelectArg("fileName", file.getFileName());
        try {
            DeleteBuilder<ReplayFile, Long> deleteBuilder = dao.deleteBuilder();
            deleteBuilder.where()
                    .eq("fileName", selectArg);
            dao.delete(deleteBuilder.prepare());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private Stream<ReplayFile> getAllByFileNames(List<String> fileNames) {
        try {
            return dao.queryForAll().stream().filter(file -> fileNames.contains(file.getFileName()));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void close() throws IOException {
        connectionSource.closeQuietly();
    }
}

@@ -763,53 +763,8 @@
 er;%0A
-import com.j256.ormlite.stmt.PreparedDelete;%0A
 impo
@@ -1305,40 +1305,8 @@
 ors;
-%0Aimport java.util.stream.Stream;
 %0A%0A/*
@@ -2573,32 +2573,14 @@
     
-List%3CString%3E fileNames =
+return
  acc
@@ -2726,106 +2726,27 @@
 map(
-ReplayFile::getFileName).collect(Collectors.toList());%0A%0A        return getAllByFileNames(fileNames
+this::getByFileName
 )%0A  
@@ -3781,15 +3781,8 @@
 ate 
-Stream%3C
 Repl
@@ -3787,24 +3787,20 @@
 playFile
-%3E
  get
-All
 ByFileNa
@@ -3805,32 +3805,36 @@
 Name
-s(List%3CString%3E fileNames
+(final ReplayFile replayFile
 ) %7B%0A
@@ -3863,95 +3863,362 @@
     
-return dao.queryForAll().stre
+final SelectArg selectArg = new SelectArg(%22fileName%22, replayFile.getFileN
 am
+e
 ()
-.filter(file -%3E fileNames.contains(file.getFileName())
+);%0A            final PreparedQuery%3CReplayFile%3E query = dao.queryBuilder()%0A                    .where().eq(%22fileName%22, selectArg)%0A                    .prepare();%0A%0A            return dao.query(query).stream()%0A                    .findAny()%0A                    .orElse(replayFile
 );%0A 
@@ -4296,32 +4296,33 @@
 n(e);%0A        %7D%0A
+%0A
     %7D%0A%0A    @Over

revert speed up startup (reverted from commit 3ffcb22c347b2a1bb9e16235bb5fffe71acc4f62)