/* * Copyright 2013 serso aka se.solovyev * * 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. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Contact details * * Email: se.solovyev@gmail.com * Site: http://se.solovyev.org */ package org.solovyev.android.calculator.entities; import android.app.Application; import android.content.SharedPreferences; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import com.squareup.otto.Bus; import org.json.JSONArray; import org.json.JSONException; import org.solovyev.android.Check; import org.solovyev.android.calculator.AppModule; import org.solovyev.android.calculator.EntitiesRegistry; import org.solovyev.android.calculator.ErrorReporter; import org.solovyev.android.calculator.json.Json; import org.solovyev.android.calculator.json.Jsonable; import org.solovyev.android.io.FileSaver; import org.solovyev.android.io.FileSystem; import org.solovyev.common.math.MathEntity; import org.solovyev.common.math.MathRegistry; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Named; import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.Executor; public abstract class BaseEntitiesRegistry<T extends MathEntity> implements EntitiesRegistry<T> { @Nonnull protected final Object lock = this; @Nonnull private final MathRegistry<T> mathRegistry; @NonNull private final WriteTask writeTask = new WriteTask(); @Inject public Handler handler; @Inject public SharedPreferences preferences; @Inject public Application application; @Inject public Bus bus; @Inject public ErrorReporter errorReporter; @Inject public FileSystem fileSystem; @Inject @Named(AppModule.THREAD_BACKGROUND) public Executor backgroundThread; @Inject @Named(AppModule.DIR_FILES) public File filesDir; @Nonnull private final Map<String, Integer> descriptions = new HashMap<>(); // synchronized on lock private boolean initialized; protected BaseEntitiesRegistry(@Nonnull MathRegistry<T> mathRegistry) { this.mathRegistry = mathRegistry; } protected void addDescription(@Nonnull String name, @StringRes int description) { descriptions.put(name, description); } @Nullable @Override public String getDescription(@Nonnull String name) { final Integer description = descriptions.get(name); if (description == null || description == 0) { return null; } return application.getResources().getString(description); } @Override public void init() { setInitialized(); } @NonNull protected final <E> List<E> loadEntities(@NonNull Json.Creator<E> creator) { final File file = getEntitiesFile(); if (file == null) { return Collections.emptyList(); } try { return Json.load(file, fileSystem, creator); } catch (IOException | JSONException e) { errorReporter.onException(e); } return Collections.emptyList(); } protected final void setInitialized() { synchronized (lock) { Check.isTrue(!initialized); initialized = true; } } public boolean isInitialized() { synchronized (lock) { return initialized; } } @Override public void save() { handler.removeCallbacks(writeTask); handler.postDelayed(writeTask, 500); } @Nonnull @Override public List<T> getEntities() { return mathRegistry.getEntities(); } @Nonnull @Override public List<T> getSystemEntities() { return mathRegistry.getSystemEntities(); } @Override public T addOrUpdate(@Nonnull T t) { final T entity = mathRegistry.addOrUpdate(t); if (!entity.isSystem() && isInitialized()) { save(); } return entity; } @Nullable protected T addSafely(@Nonnull T entity) { try { return addOrUpdate(entity); } catch (Exception e) { errorReporter.onException(e); } return null; } @Override public void remove(@Nonnull T var) { mathRegistry.remove(var); save(); } @Nonnull @Override public List<String> getNames() { return mathRegistry.getNames(); } @Override public boolean contains(@Nonnull String name) { return mathRegistry.contains(name); } @Override public T get(@Nonnull String name) { return mathRegistry.get(name); } @Override public T getById(@Nonnull Integer id) { return mathRegistry.getById(id); } @Nullable protected abstract Jsonable toJsonable(@NonNull T entity); @Nullable protected abstract File getEntitiesFile(); private class WriteTask implements Runnable { @Override public void run() { Check.isMainThread(); final File file = getEntitiesFile(); if (file == null) { return; } final List<Jsonable> entities = new ArrayList<>(); for (T entity : getEntities()) { if (entity.isSystem()) { continue; } final Jsonable jsonable = toJsonable(entity); if (jsonable != null) { entities.add(jsonable); } } backgroundThread.execute(new Runnable() { @Override public void run() { final JSONArray array = Json.toJson(entities); try { FileSaver.save(file, array.toString()); } catch (IOException e) { errorReporter.onException(e); } } }); } } }