/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.dlect.provider;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.dlect.encryption.DatabaseDecryptionHandler;
import org.dlect.exception.DLectException;
import org.dlect.exception.DLectExceptionCause;
import org.dlect.file.FileController;
import org.dlect.helper.Conditions;
import org.dlect.immutable.model.ImmutableLectureDownload;
import org.dlect.immutable.model.ImmutableSemester;
import org.dlect.immutable.model.ImmutableSubject;
import org.dlect.logging.ProviderLogger;
import org.dlect.model.Database;
import org.dlect.model.Lecture;
import org.dlect.model.LectureDownload;
import org.dlect.model.Semester;
import org.dlect.model.Subject;
import org.dlect.provider.helper.WrappedProviderLectureHelper;
import org.dlect.provider.helper.WrappedProviderSubjectHelper;
import org.dlect.provider.objects.ImmutableSubjectData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.dlect.helper.Conditions.checkNonNull;
import static org.dlect.model.helper.CommonSettingNames.*;
/**
*
* @author lee
*/
public class WrappedProvider {
public static final Logger LOGGER = LoggerFactory.getLogger(WrappedProvider.class);
private static final ImmutableSet<ImmutableSubject> EMPTY_SUBJECTS = ImmutableSet.of();
private final Database d;
private final DatabaseDecryptionHandler deh;
private final FileController fc;
private final Provider p;
private boolean hasInit = false;
public WrappedProvider(Provider p, Database d, FileController fc) {
checkNonNull(p, "Provider");
checkNonNull(d, "Database");
checkNonNull(fc, "File Controller");
this.p = p;
this.d = d;
this.deh = new DatabaseDecryptionHandler(d);
this.fc = fc;
}
public void doLogin() throws DLectException {
Optional<String> usr = deh.getEncryptedSetting(USERNAME);
Optional<String> pwd = deh.getEncryptedSetting(PASSWORD);
if (!usr.isPresent() || !pwd.isPresent()) {
throw new DLectException(DLectExceptionCause.BAD_CREDENTIALS);
}
doInit();
LoginProvider lp = p.getLoginProvider();
lp.doLogin(usr.get(), pwd.get());
}
private void ensureExists(Subject s, Lecture l, LectureDownload ld) {
if (!s.getLectures().contains(l)) {
throw new IllegalArgumentException("The lecture is not contained in the subject");
}
if (!l.getLectureDownloads().containsValue(ld)) {
throw new IllegalArgumentException("The download is not contained in the lecture");
}
for (Semester semester : d.getSemesters()) {
if (semester.getSubjects().contains(s)) {
return;
}
}
throw new IllegalArgumentException("The subject is not contained in the database.");
}
protected Semester findSubject(Subject s) {
for (Semester semester : d.getSemesters()) {
for (Subject subject : semester.getSubjects()) {
if (Objects.equal(s, subject)) {
return semester;
}
}
}
return null;
}
public void getLecturesIn(Subject s) throws DLectException {
Conditions.checkNonNull(s, "Subject");
Semester sem = findSubject(s);
if (sem == null) {
throw new IllegalArgumentException("Subject is not in the configured database");
}
ImmutableSubject is = ImmutableSubject.from(s);
ImmutableSemester imSem = new ImmutableSemester(sem.getNum(), sem.getLongName(), sem.getCoursePostfixName(), EMPTY_SUBJECTS);
LectureProvider lp = p.getLectureProvider();
if (lp == null) {
throw new DLectException(DLectExceptionCause.PROVIDER_CONTRACT, "The provider(" + p + ") failed to return a valid LectureProvider");
}
ImmutableSubjectData data = lp.getLecturesIn(imSem, is);
WrappedProviderLectureHelper.mergeSubjectData(s, data);
}
public void getSubjects() throws DLectException {
Multimap<ImmutableSemester, ImmutableSubject> subjects = p.getSubjectProvider().getSubjects();
WrappedProviderSubjectHelper.insertSemestersIntoDatabase(d, subjects);
}
public void doDownload(Subject s, Lecture l, LectureDownload ld) throws DLectException {
// TODO(Later) consider moving this into another class so that items can listen to progress events.
ensureExists(s, l, ld);
InputStream is = new BufferedInputStream(p.getDownloadProvider().getDownloadStreamFor(ImmutableLectureDownload.from(ld)));
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(fc.getFileForDownload(s, l, ld)));
} catch (IOException ex) {
try {
is.close();
} catch (IOException ex1) {
ProviderLogger.LOGGER.error("Error closing input stream for download.", ex1);
}
throw new DLectException(DLectExceptionCause.DISK_ERROR, "The file was not found. "
+ "This is a problem with "
+ "getFileForDownload(" + s
+ ", " + l + ", " + ld + ")", ex);
}
try (InputStream iss = is; OutputStream oss = os) {
byte[] load = new byte[8192];
int lastRead;
int totalRead = 0;
do {
try {
lastRead = iss.read(load);
} catch (IOException e) {
throw new DLectException(DLectExceptionCause.NO_CONNECTION, "Failed to read from download stream.", e);
}
if (lastRead < 0) {
break;
}
totalRead += lastRead;
try {
oss.write(load, 0, lastRead);
} catch (IOException ex) {
throw new DLectException(DLectExceptionCause.DISK_ERROR);
}
} while (lastRead >= 0);
} catch (IOException ex) {
ProviderLogger.LOGGER.error("Error closing stream for download.", ex);
}
}
public synchronized void doInit() throws DLectException {
if (!hasInit) {
p.init();
hasInit = true;
}
}
}