/* Copyright (C) 2006 Christian Schneider
*
* This file is part of Nomad.
*
* Nomad is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Nomad 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Nomad; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sf.nmedit.jsynth.clavia.nordmodular.worker;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.SwingUtilities;
import net.sf.nmedit.jnmprotocol2.GetPatchListMessage;
import net.sf.nmedit.jnmprotocol2.NmProtocolListener;
import net.sf.nmedit.jnmprotocol2.PatchListEntry;
import net.sf.nmedit.jnmprotocol2.PatchListMessage;
import net.sf.nmedit.jsynth.SynthException;
import net.sf.nmedit.jsynth.clavia.nordmodular.NmBank;
import net.sf.nmedit.jsynth.clavia.nordmodular.NordModular;
public class GetPatchListWorker extends NmProtocolListener implements ScheduledWorker
{
private NordModular synth;
private NmBank bank;
private int beginIndex;
private int endIndex;
private int nextIndex;
private boolean error = false;
private List<String> patches;
private int state = REQUEST_PATCH_LIST;
private static final int REQUEST_PATCH_LIST = 0;
private static final int AWAIT_REPLY = 1;
private static final int COMPLETE = 2;
private long timeout = 0;
private boolean replyAccepted = false;
private boolean installed = false;
public GetPatchListWorker(NmBank bank, int beginIndex, int endIndex)
{
if (endIndex<beginIndex || beginIndex<0 || endIndex>NmBank.PATCH_COUNT)
throw new IllegalArgumentException("invalid beginIndex:"+beginIndex+", endIndex:"+endIndex);
this.synth = bank.getSynthesizer();
this.bank = bank;
this.beginIndex = beginIndex;
this.nextIndex = beginIndex;
this.endIndex = endIndex;
this.patches = new ArrayList<String>(endIndex-beginIndex);
}
private void install()
{
if (!installed)
{
installed = true;
bank.getSynthesizer().addProtocolListener(this);
}
}
private void uninstall()
{
if (installed)
{
installed = false;
bank.getSynthesizer().removeProtocolListener(this);
}
}
public void aborted()
{
error = true;
uninstall();
}
public void sendRequest()
{
install();
bank.getSynthesizer().getScheduler().offer(this);
}
public boolean isWorkerFinished()
{
// TODO Auto-generated method stub
return error || (!synth.isConnected()) || requestComplete();
}
public void runWorker() throws SynthException
{
if (state == COMPLETE)
return;
if (state == REQUEST_PATCH_LIST)
{
timeout = System.currentTimeMillis()+3000;
state = AWAIT_REPLY;
replyAccepted = false;
GetPatchListMessage get = new GetPatchListMessage(bank.getBankIndex(), nextIndex);
try
{
synth.getProtocol().send(get);
}
catch (Exception e)
{
error = true;
e.printStackTrace();
}
return;
}
// await reply
if (!replyAccepted)
{
if (System.currentTimeMillis()>timeout)
throw new SynthException("timeout while waiting for patch list: "+3000);
return;
}
// reply accepted
if (!requestComplete())
{
state = REQUEST_PATCH_LIST;
return;
}
// request complete
state = COMPLETE;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
uninstall();
// should all work through callbacks from messages
updateBank();
}
}
);
}
private int updateBeginIndex = -1;
private void updateBank()
{
if (updateBeginIndex<0)
updateBeginIndex = beginIndex;
int updateEndIndex = beginIndex+patches.size();
if (updateBeginIndex<updateEndIndex)
{
Collection<String> c = patches.subList(updateBeginIndex-beginIndex, updateEndIndex-beginIndex);
if (updateBeginIndex+c.size()<=bank.getPatchCount()) // avoid IllegalArgumentException
bank.updatePatchList(updateBeginIndex, c);
//else
// TODO debug this case: happens if storing patch over existing bank position
}
updateBeginIndex = updateEndIndex;
}
private boolean requestComplete()
{
return nextIndex>=endIndex;
}
private int previousNextIndex = Integer.MIN_VALUE;
public void messageReceived(PatchListMessage message)
{
if (state != AWAIT_REPLY)
return;
replyAccepted = true;
List<PatchListEntry> list = message.getEntries();
if (previousNextIndex >= nextIndex || list.isEmpty())
{
fillList(endIndex);
nextIndex = endIndex;
return;
}
previousNextIndex = nextIndex;
for (PatchListEntry e: list)
{
if (e.getPosition()<0 || e.getSection()<0 || (e.getSection()>bank.getBankIndex()))
{
// positions containing no patches
fillList(endIndex);
nextIndex = endIndex;
return;
// complete
}
// positions containing no patches
fillList(e.getPosition());
String name = e.getName();
if (name == null) name = "";
patches.add(name);
nextIndex++;
}
updateBank();
}
private void fillList(int end)
{
while (nextIndex<end)
{
patches.add(null);
nextIndex++;
}
}
}