package com.csound.wizard.model;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.collections4.iterators.ReverseListIterator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.SerializationUtils;
import com.csound.wizard.Settings;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Environment;
import android.util.Base64;
public class Model {
private HashMap<String,TrackData> tracks = new HashMap<String,TrackData>();
private List<Playlist> playlists;
private int currentPlaylist = 0;
private int currentTrack = 0;
private Settings settings;
private static int RECENT_MAX_SIZE = 10;
private RecentQueue<TrackRef> recentTracks;
private RecentQueue<String> recentPlaylists;
public Model() {
playlists = new ArrayList<Playlist>();
recentTracks = new RecentQueue<TrackRef>(RECENT_MAX_SIZE);
recentPlaylists = new RecentQueue<String>(RECENT_MAX_SIZE);
settings = new Settings();
}
private static final String
TEST_DIR = "test-json",
TEST_DIR_NAME = "Demo";
private Playlist copyTestDataToCard(Context ctx) {
File sdCard = Environment.getExternalStorageDirectory();
String dirName = sdCard.getAbsolutePath() + "/demo-csound-wizard-test/";
new File(dirName).mkdirs();
List<String> names = new ArrayList<String>();
try {
for(String f : ctx.getAssets().list(TEST_DIR)){
String fileName = dirName + f;
FileUtils.copyInputStreamToFile(ctx.getAssets().open(TEST_DIR + "/" + f), new File(fileName));
names.add(fileName);
tracks.put(fileName, new TrackData());
}
} catch (Exception e) {
e.printStackTrace();
}
return new Playlist(TEST_DIR_NAME, names);
}
private boolean isLoadedTest = false;
public void loadTestData(Context ctx) {
if (!isLoadedTest) {
Iterator<Playlist> it = playlists.iterator();
while (it.hasNext()) {
Playlist p = it.next();
if (p.getName().equals(TEST_DIR_NAME)) {
it.remove();
}
}
playlists.add(copyTestDataToCard(ctx));
setCurrentPlaylist(TEST_DIR_NAME);
isLoadedTest = true;
}
}
private Model(ModelSettings m) {
tracks = m.tracks;
playlists = m.playlists;
currentPlaylist = m.currentPlaylist;
currentTrack = m.currentTrack;
recentTracks = m.recentTracks;
recentPlaylists = m.recentPlaylists;
settings = m.settings;
}
private static class ModelSettings implements Serializable {
private static final long serialVersionUID = 1832463543815414805L;
private HashMap<String,TrackData> tracks;
private List<Playlist> playlists;
private int currentPlaylist = 0;
private int currentTrack = 0;
private Settings settings;
private RecentQueue<TrackRef> recentTracks;
private RecentQueue<String> recentPlaylists;
public ModelSettings(Model m) {
tracks = m.tracks;
playlists = m.playlists;
currentPlaylist = m.currentPlaylist;
currentTrack = m.currentTrack;
recentTracks = m.recentTracks;
recentPlaylists = m.recentPlaylists;
settings = m.settings;
}
}
private static final String settingsFile = "csd-wizard-settings";
private static final String modelKey = "model";
public static void clear(Context ctx) {
SharedPreferences pref = ctx.getSharedPreferences(settingsFile, 0);
SharedPreferences.Editor editor = pref.edit();
editor.remove(modelKey);
editor.commit();
}
public void save(Context ctx) {
SharedPreferences pref = ctx.getSharedPreferences(settingsFile, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putString(modelKey, Base64.encodeToString(SerializationUtils.serialize(new ModelSettings(this)), Base64.DEFAULT));
editor.commit();
}
public static Model load(Context ctx) {
SharedPreferences pref = ctx.getSharedPreferences(settingsFile, 0);
String text = pref.getString(modelKey, "");
if (text.isEmpty()) {
return new Model();
} else {
return new Model ((ModelSettings) SerializationUtils.deserialize(Base64.decode(text, Base64.DEFAULT)));
}
}
public List<Playlist> getPlaylists() {
return playlists;
}
public Playlist getCurrentPlaylist() {
return playlists.get(currentPlaylist);
}
public void setCurrentPlaylist(int n) {
if (n != currentPlaylist) {
logPlaylistChoice(n);
currentTrack = 0;
currentPlaylist = n;
}
}
public void addPlaylist(String name) {
playlists.add(new Playlist(name));
}
public Boolean trackExists(int n) {
return getCurrentPlaylist().getTracks().size() > n;
}
public int getCurrentTrackId() {
return currentTrack;
}
public int getCurrentPlaylistId() {
return currentPlaylist;
}
public String getPlaylistName(int n) {
return playlists.get(n).getName();
}
public Playlist getPlaylistById(int n) {
return playlists.get(n);
}
public String getTrackName(int n) {
return FilenameUtils.getName(getCurrentPlaylist().getTracks().get(n));
}
public String getCurrentTrackName() {
return getTrackName(currentTrack);
}
public void removeTrackById(Playlist p, int location) {
TrackRef ref = p.getTrackRefs().get(location);
recentTracks.remove(ref);
p.removeTrackById(location);
}
public void removePlaylistById(int location) {
String name = playlists.get(location).getName();
recentPlaylists.remove(name);
playlists.remove(location);
if (location == currentPlaylist && !recentPlaylists.isEmpty()) {
String nextName = recentPlaylists.get(0);
int i = 0;
while (!nextName.equals(playlists.get(i))) {
i++;
}
currentPlaylist = i;
currentTrack = 0;
} else if (location == currentPlaylist && recentPlaylists.isEmpty()) {
currentPlaylist = 0;
currentTrack = 0;
}
}
public Track getCurrentTrack() {
String name = getCurrentPlaylist().getTracks().get(currentTrack);
return new Track(name, tracks.get(name));
}
public void saveTrack(String path) {
tracks.put(path, new TrackData());
getCurrentPlaylist().addTrack(path);
}
public void saveTracksFromDir(String dir) {
String[] exts = {"csd"};
Collection<File> fs = FileUtils.listFiles(new File(dir), exts, true);
for (File f: fs) {
saveTrack(f.getAbsolutePath());
}
}
public void saveLink(String trackName) {
getCurrentPlaylist().getTracks().add(trackName);
}
public void setCurrentTrack(int n) {
logTrackChoice(n);
currentTrack = n;
}
public void setCurrentTrack(TrackRef ref) {
logTrackChoice(ref);
currentPlaylist = playlistPosition(ref.getPlaylistName());
currentTrack = trackPosition(currentPlaylist, ref);
}
public void setCurrentPlaylist(String name) {
setCurrentPlaylist(playlistPosition(name));
}
private int playlistPosition(String ref) {
int i = 0;
while (!playlists.get(i).getName().equals(ref)) {
i++;
}
if (i == playlists.size()) {
return 0;
}
return i;
}
private int trackPosition(int playlistId, TrackRef ref) {
List<String> ts = playlists.get(playlistId).getTracks();
String trackName = ref.getTrackName();
int i = 0;
while (!ts.get(i).equals(trackName)) {
i++;
}
return i;
}
public void nextTrack() {
currentTrack = withinSize(currentTrack + 1, getCurrentPlaylist().getTracks().size());
logTrackChoice(currentTrack);
}
public void prevTrack() {
currentTrack = withinSize(currentTrack - 1, getCurrentPlaylist().getTracks().size());
logTrackChoice(currentTrack);
}
private int withinSize(int n, int size) {
return (size + n) % size;
}
public List<String> getPlaylistNames() {
List<String> res = new ArrayList<String>();
for (Playlist p: playlists) {
res.add(p.getName());
}
return res;
}
public List<String> getRecentPlaylistsNames() {
return IteratorUtils.toList(new ReverseListIterator<String>(IteratorUtils.toList(recentPlaylists.iterator())));
}
public List<TrackRef> getRecentTracks() {
return IteratorUtils.toList(new ReverseListIterator<TrackRef>(IteratorUtils.toList(recentTracks.iterator())));
}
public List<String> getCurrentTrackNames() {
List<String> res = new ArrayList<String>();
for (String s: getCurrentPlaylist().getTracks()) {
res.add(FilenameUtils.getName(s));
}
return res;
}
public void removeStubs() {
cleanTracks();
cleanRecentTracks();
cleanPlaylists();
}
private void cleanTracks() {
Iterator<String> it = tracks.keySet().iterator();
while (it.hasNext()) {
if (!(new File(it.next()).exists())) {
it.remove();
}
}
}
private void cleanRecentTracks() {
Iterator<TrackRef> it = recentTracks.iterator();
while (it.hasNext()) {
if (!(new File(it.next().getTrackName()).exists())) {
it.remove();
}
}
}
private void cleanPlaylists() {
for (Playlist p: playlists) {
cleanPlaylist(p);
}
}
private void cleanPlaylist(Playlist p) {
Iterator<String> it = p.getTracks().iterator();
while (it.hasNext()) {
if (!(tracks.containsKey(it.next()))) {
it.remove();
}
}
}
private void logTrackChoice(int id) {
Playlist p = getCurrentPlaylist();
String playlistName = p.getName();
String trackName = p.getTracks().get(id);
recentTracks.add(new TrackRef(trackName, playlistName));
}
private void logTrackChoice(TrackRef ref) {
recentTracks.add(ref);
}
private void logPlaylistChoice(int id) {
recentPlaylists.add(playlists.get(id).getName());
}
public Settings getSettings() {
return settings;
}
}