/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.pocketmusic.note;
import android.util.LongSparseArray;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class Track implements Serializable {
private static final long serialVersionUID = 7483021689872527955L;
private MusicalInstrument instrument;
private LongSparseArray<List<NoteEvent>> events;
private MusicalKey key;
private long lastTick;
public Track(MusicalKey key, MusicalInstrument instrument) {
this.events = new LongSparseArray<>();
this.instrument = instrument;
this.key = key;
this.lastTick = 0;
}
public Track(Track track) {
this.events = new LongSparseArray<>();
this.instrument = track.getInstrument();
this.key = track.getKey();
this.lastTick = track.getLastTick();
for (long tick : track.getSortedTicks()) {
List<NoteEvent> noteEventList = new LinkedList<>();
this.events.put(tick, noteEventList);
for (NoteEvent noteEvent : track.getNoteEventsForTick(tick)) {
noteEventList.add(new NoteEvent(noteEvent));
}
}
}
public MusicalInstrument getInstrument() {
return instrument;
}
public MusicalKey getKey() {
return key;
}
public void addNoteEvent(long tick, NoteEvent noteEvent) {
List<NoteEvent> noteEventList;
if (events.get(tick) != null) {
noteEventList = events.get(tick);
} else {
noteEventList = new LinkedList<>();
events.put(tick, noteEventList);
}
if (!noteEvent.isNoteOn()) {
lastTick = tick;
}
if (!eventListAlreadyContainsNoteEventWithTick(tick, noteEvent)) {
noteEventList.add(noteEvent);
}
}
private boolean eventListAlreadyContainsNoteEventWithTick(long tick, NoteEvent noteEvent) {
for (int i = 0; i < events.size(); i++) {
long key = events.keyAt(i);
if (key == tick && events.get(key).contains(noteEvent)) {
return true;
}
}
return false;
}
public List<NoteEvent> getNoteEventsForTick(long tick) {
List<NoteEvent> noteEvents = events.get(tick);
Collections.sort(noteEvents, new Comparator<NoteEvent>() {
@Override
public int compare(NoteEvent noteEvent1, NoteEvent noteEvent2) {
if (noteEvent1.isNoteOn() == noteEvent2.isNoteOn()) {
return 0;
} else if (noteEvent1.isNoteOn()) {
return 1;
} else {
return -1;
}
}
});
return noteEvents;
}
public Set<Long> getSortedTicks() {
Set<Long> treeSet = new TreeSet<>();
for (int i = 0; i < events.size(); i++) {
treeSet.add(events.keyAt(i));
}
return treeSet;
}
public int size() {
int size = 0;
for (Long sortedTick : getSortedTicks()) {
size += events.get(sortedTick).size();
}
return size;
}
public long getLastTick() {
return lastTick;
}
public long getTotalTimeInMilliseconds() {
return NoteLength.tickToMilliseconds(lastTick);
}
public boolean empty() {
return (0 == size());
}
@Override
public int hashCode() {
int primeWithGoodCollisionPrevention = 31;
int hashCode = 18;
hashCode = primeWithGoodCollisionPrevention * hashCode + instrument.hashCode();
hashCode = primeWithGoodCollisionPrevention * hashCode + events.hashCode();
hashCode = primeWithGoodCollisionPrevention * hashCode + key.hashCode();
hashCode = primeWithGoodCollisionPrevention * hashCode + (int) lastTick;
return hashCode;
}
@Override
public boolean equals(Object obj) {
if ((obj == null) || !(obj instanceof Track)) {
return false;
}
Track track = (Track) obj;
if (track.getInstrument() != getInstrument()) {
return false;
}
if (track.getKey() != getKey()) {
return false;
}
Set<Long> ownTrackTicks = getSortedTicks();
Set<Long> otherTrackTicks = track.getSortedTicks();
if (otherTrackTicks.equals(ownTrackTicks)) {
for (long tick : ownTrackTicks) {
List<NoteEvent> ownNoteEventList = getNoteEventsForTick(tick);
List<NoteEvent> otherNoteEventList = track.getNoteEventsForTick(tick);
if (!ownNoteEventList.equals(otherNoteEventList)) {
return false;
}
}
return true;
}
return false;
}
@Override
public String toString() {
return "[Track] instrument=" + instrument + " key=" + key + " size=" + size();
}
public boolean isEmpty() {
return size() == 0;
}
}