package acousticfield3d.gui.panels;

import acousticfield3d.algorithms.CalcField;
import acousticfield3d.gui.MainForm;
import acousticfield3d.math.M;
import acousticfield3d.math.Vector2f;
import acousticfield3d.scene.Entity;
import acousticfield3d.scene.MeshEntity;
import acousticfield3d.workers.PlayerThread;
import acousticfield3d.simulation.AnimKeyFrame;
import acousticfield3d.simulation.Animation;
import acousticfield3d.simulation.Transducer;
import acousticfield3d.utils.DialogUtils;
import acousticfield3d.utils.FileUtils;
import acousticfield3d.utils.Parse;
import acousticfield3d.utils.TextFrame;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Asier
 */
public class AnimPanel extends javax.swing.JPanel {
    public final MainForm mf;
    
    public Animation currentAnimation;
    Animation emptyAnimation;
    PlayerThread player;
    
    public AnimPanel(MainForm mf) {
        this.mf = mf;
        
        emptyAnimation = new Animation();
        currentAnimation = emptyAnimation;
        
        initComponents();
        
        currentAnimation = emptyAnimation;
        statusList.setModel( currentAnimation.keyFrames );
        animationList.setModel( mf.simulation.animations );
        
        player = new PlayerThread(this, 25.0f);
        player.start();
    }

    public void initSimulation() {
        currentAnimation = emptyAnimation;
        statusList.setModel(currentAnimation.keyFrames);
        animationList.setModel(mf.simulation.animations);
    }
        
    public float getCurrentTime() {
        return player.getCurrentTime();
    }
    
    public Animation[] getSelectedAnimations(){
        final int[] selectedIndices = animationList.getSelectedIndices();
        final int size = selectedIndices.length;
        final Animation[] anims = new Animation[size];
        for(int i = 0; i < size; ++i){
            anims[i] = mf.simulation.getAnimations().getAt(selectedIndices[i]);
        }
        return anims;
    }
       
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        wraperGroup = new javax.swing.ButtonGroup();
        addAnim = new javax.swing.JButton();
        delAnim = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        animationList = new javax.swing.JList();
        addStatus = new javax.swing.JButton();
        delStatus = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        statusList = new javax.swing.JList();
        stopWrap = new javax.swing.JRadioButton();
        repeatWrap = new javax.swing.JRadioButton();
        pingpongWrap = new javax.swing.JRadioButton();
        stopButton = new javax.swing.JButton();
        playToggle = new javax.swing.JToggleButton();
        playSlider = new javax.swing.JSlider();
        jLabel13 = new javax.swing.JLabel();
        durationText = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        waitText = new javax.swing.JTextField();
        prevButton = new javax.swing.JButton();
        nextButton = new javax.swing.JButton();
        currentFrameText = new javax.swing.JLabel();

        addAnim.setText("+");
        addAnim.setToolTipText("Add animation");
        addAnim.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addAnimActionPerformed(evt);
            }
        });

        delAnim.setText("-");
        delAnim.setToolTipText("remove animation");
        delAnim.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                delAnimActionPerformed(evt);
            }
        });

        animationList.setModel(mf.simulation.getAnimations());
        animationList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                animationListMouseClicked(evt);
            }
        });
        animationList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                animationListValueChanged(evt);
            }
        });
        jScrollPane1.setViewportView(animationList);

        addStatus.setText("+");
        addStatus.setToolTipText("add keyframe");
        addStatus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addStatusActionPerformed(evt);
            }
        });

        delStatus.setText("-");
        delStatus.setToolTipText("remove keyframe");
        delStatus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                delStatusActionPerformed(evt);
            }
        });

        statusList.setModel(currentAnimation.getKeyFrames());
        statusList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                statusListMouseClicked(evt);
            }
        });
        jScrollPane2.setViewportView(statusList);

        wraperGroup.add(stopWrap);
        stopWrap.setText("stop");
        stopWrap.setToolTipText("stops when the animation reaches the end");

        wraperGroup.add(repeatWrap);
        repeatWrap.setText("repeat");
        repeatWrap.setToolTipText("repeats from the beginning when the animation reaches the end");

        wraperGroup.add(pingpongWrap);
        pingpongWrap.setSelected(true);
        pingpongWrap.setText("pingpong");
        pingpongWrap.setToolTipText("repeat animation in pingpong");

        stopButton.setText("Stop");
        stopButton.setToolTipText("stop current animation");
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });

        playToggle.setMnemonic('a');
        playToggle.setText("Play");
        playToggle.setToolTipText("play current animation");
        playToggle.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                playToggleActionPerformed(evt);
            }
        });

        playSlider.setPaintTicks(true);
        playSlider.setValue(0);
        playSlider.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                playSliderStateChanged(evt);
            }
        });

        jLabel13.setText("Periods:");

        durationText.setText("1");
        durationText.setToolTipText("durations in periods of the point (only for some boards)");
        durationText.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                durationTextActionPerformed(evt);
            }
        });

        jLabel1.setText("Wait:");

        waitText.setText("200");
        waitText.setToolTipText("milliseconds to wait between keyframes");

        prevButton.setText("Prev");
        prevButton.setToolTipText("previous keyframe");
        prevButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                prevButtonActionPerformed(evt);
            }
        });

        nextButton.setText("Next");
        nextButton.setToolTipText("next keyframe");
        nextButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                nextButtonActionPerformed(evt);
            }
        });

        currentFrameText.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        currentFrameText.setText("0");
        currentFrameText.setToolTipText("current frame");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel13)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(durationText, javax.swing.GroupLayout.PREFERRED_SIZE, 68, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(playSlider, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(addAnim, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(delAnim, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(addStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(delStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(waitText))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(prevButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(nextButton))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(stopWrap)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(repeatWrap)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(pingpongWrap)
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(playToggle)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(currentFrameText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(stopButton)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(addAnim)
                    .addComponent(delAnim)
                    .addComponent(addStatus)
                    .addComponent(delStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 62, Short.MAX_VALUE)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
                .addGap(11, 11, 11)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel13)
                    .addComponent(durationText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(pingpongWrap, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(stopWrap, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(repeatWrap)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(playSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(waitText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(playToggle)
                    .addComponent(currentFrameText)
                    .addComponent(stopButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(prevButton)
                    .addComponent(nextButton))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    
    public int getCurrentFrame(){
        return player.getCurrentFrame();
    }
    
    public Animation getCurrentAnimation() {
        return currentAnimation;
    }
        
    public void setCurrentFrame(float value){
        currentFrameText.setText(value + "");
    }
    
    public boolean isPlaying(){
        return playToggle.isSelected();
    }
    
    public void setPlaying(boolean playing){
        playToggle.setSelected( playing );
    }
    
    
    public boolean isWrapStop(){
        return stopWrap.isSelected();
    }
    public boolean isWrapRepeat(){
        return repeatWrap.isSelected();
    }
    public boolean isWrapPingPong(){
        return pingpongWrap.isSelected();
    }

    public float getWaitTime(){
        return Parse.toFloat( waitText.getText() );
    }
    
     public void updateTimeSlider(float p){
        int pi = (int)(p*100.0f);
        playSlider.setValue(pi);
    }
     
    private void addAnimActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addAnimActionPerformed
        String name = DialogUtils.getStringDialog(this, "Name?", "anim" + mf.simulation.animations.getSize());
        if(name != null){
            final Animation anim = createNewAnimation(name);
            mf.simulation.animations.add( anim );
        }
    }//GEN-LAST:event_addAnimActionPerformed

    public Animation createNewAnimation(String name){
        Animation anim = new Animation();
        anim.name = name;
        final int size = mf.simulation.animations.getSize();
        anim.setNumber(size == 0 ? 0 : (mf.simulation.animations.getElements().get(size - 1).getNumber() + 1));
        return anim;
    }
    
    private void delAnimActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_delAnimActionPerformed
        int[] selectedIndices = animationList.getSelectedIndices();
        mf.simulation.animations.delete(selectedIndices);
    }//GEN-LAST:event_delAnimActionPerformed

    private void animationListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_animationListValueChanged
        int index = animationList.getSelectedIndex();
        if(index != -1){
            Animation anim = mf.simulation.animations.getAt(index);
            currentAnimation = anim;
        }else{
            currentAnimation = emptyAnimation;
        }
        statusList.setModel( currentAnimation.getKeyFrames() );  
    }//GEN-LAST:event_animationListValueChanged

    public void addKeyFrame(){
        if (currentAnimation != emptyAnimation){
            snapAndAddNewKeyFrame( currentAnimation );
        }
    }
    
    private void addStatusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addStatusActionPerformed
        addKeyFrame();
    }//GEN-LAST:event_addStatusActionPerformed

    private AnimKeyFrame snapAndAddNewKeyFrame(final Animation anim){
        AnimKeyFrame akf = new AnimKeyFrame();
        final int size = anim.keyFrames.getSize();
        akf.setNumber(size == 0 ? 0 : (anim.keyFrames.getElements().get(size - 1).getNumber() + 1));
        akf.duration = Parse.toFloat(durationText.getText());
        akf.snap(mf.simulation);
        anim.keyFrames.add(akf);
        return akf;
    }
    
   
    private void delStatusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_delStatusActionPerformed
        int[] selected = statusList.getSelectedIndices();
        currentAnimation.keyFrames.delete(selected);
    }//GEN-LAST:event_delStatusActionPerformed

    private void statusListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_statusListMouseClicked
        //apply current akf
        if (evt.getClickCount() == 2){
            int selected = statusList.getSelectedIndex();
            if(selected != -1){
                player.setCurrentFrame ( selected );
                player.applyFrame(selected);
                
                mf.transControlPanel.sendPattern();
                mf.needUpdate();
            }
        }
    }//GEN-LAST:event_statusListMouseClicked

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
        playToggle.setSelected(false);
        player.stopReproduction();
    }//GEN-LAST:event_stopButtonActionPerformed

    private void playToggleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playToggleActionPerformed
        player.playOrPause();
    }//GEN-LAST:event_playToggleActionPerformed

    public boolean shouldIgnorePlayerSlider = false;
    private void playSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_playSliderStateChanged
        if (shouldIgnorePlayerSlider){
            shouldIgnorePlayerSlider = false;
            return;
        }
        int value = playSlider.getValue();
        player.applyFrame( (int)(value / 100.0f * currentAnimation.getDuration()) ) ;
        mf.needUpdate();
    }//GEN-LAST:event_playSliderStateChanged

    private void prevButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevButtonActionPerformed
        player.prev();
    }//GEN-LAST:event_prevButtonActionPerformed

    private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextButtonActionPerformed
        player.next();
    }//GEN-LAST:event_nextButtonActionPerformed

    private void durationTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_durationTextActionPerformed
        final float duration = Parse.toFloat( durationText.getText());
        final int[] index = statusList.getSelectedIndices();
        for(int i : index){
            currentAnimation.keyFrames.getAt(i).setDuration( duration );
        }
        currentAnimation.keyFrames.updateAll();
    }//GEN-LAST:event_durationTextActionPerformed

    private void animationListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_animationListMouseClicked
        if(evt.getClickCount() == 2){
            mf.transControlPanel.sendAnim( currentAnimation.getKeyFrames().getElements() );
        }
    }//GEN-LAST:event_animationListMouseClicked


    public void setAnimationFrame(int command) {
        player.applyFrame(command);
    }
   
    public void exportRawAnimation() {
        final String file = FileUtils.selectNonExistingFile(this, ".ani");
        if (file != null){
            try {
                final byte[] data = currentAnimation.exportRaw(mf.simulation);
                FileUtils.writeBytesInFile(new File(file), data);
            } catch (IOException ex) {
                Logger.getLogger(AnimPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void importRawAnimation() {
        final String file = FileUtils.selectFile(this, "import", ".ani", null);
        if (file != null){
            try {
                final File ffile = new File(file);
                final byte[] data = FileUtils.getBytesFromFile(ffile);
                
                
                
                final Animation anim = createNewAnimation( FileUtils.getFileName(ffile) );
                mf.simulation.animations.add(anim);
                
                anim.importRaw(data, mf);
            } catch (IOException ex) {
                Logger.getLogger(AnimPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
            
        }
    }
    
    public void cloneCurrentAnimation(){
        final Animation anim = currentAnimation;
        final Animation clone = anim.createCopy();
        clone.setName( anim.getName() + "clone");
        mf.simulation.animations.add(clone);
    }
    
    public void interpolateCurrentAnimation(){
        currentAnimation.interpolate();
    }
    
    public void exportPhasesOfCurrentAnimation() {
        final StringBuilder sb = new StringBuilder();
        final Animation anim = currentAnimation;
        
        final ArrayList<AnimKeyFrame> keys = anim.getKeyFrames().getElements();
        final int nFrames = keys.size();
        if (nFrames <= 0) { return; }
        final ArrayList<Entity> points =  new ArrayList<>( keys.get(0).getPointsPositions().keySet() );
        final ArrayList<Transducer> trans =  new ArrayList<>( keys.get(0).getTransAmplitudes().keySet() );
        final int nPoints = points.size();
        final int nTrans = trans.size();
        
        for (int i = 0; i < nFrames; ++i){
            final AnimKeyFrame key = keys.get(i);
            key.apply();
            for (int j = 0; j < nPoints; ++j){
                final Entity e = points.get(j);
                final Vector2f field = CalcField.calcFieldAt(e.getTransform().getTranslation(), mf);
                float phase = field.getAngle();
                while (phase < 0) { phase+=M.PI; }
                sb.append(phase + "\t");
            }
            sb.append("\n");
        }
        TextFrame.showText("Phases", sb.toString(), this);
        
        sb.setLength(0);
        
        for (int i = 0; i < nFrames; ++i){
            final AnimKeyFrame key = keys.get(i);
            key.apply();
            for (int j = 0; j < nTrans; ++j){
                final Transducer t = trans.get(j);
                float phase = t.getPhase() * M.PI;
                while (phase < 0) { phase+=M.PI; }
                sb.append(phase + "\t");
            }
            sb.append("\n");
        }
        
        TextFrame.showText("Trans Phases", sb.toString(), this);
        
    }
    
    public void exportTransPhasePoints() {
        final StringBuilder sb = new StringBuilder();
        
        for (Transducer t : mf.simulation.transducers){
            sb.append("transducer " + t.getTransform().getTranslation().toStringSimple(" ") + " ");
            sb.append(t.getTransform().getRotation().toAngles(null).toStringSimple(" ") + " ");
            sb.append(t.getAmplitude() + " ");
            sb.append(t.getPhase()+ "\n");
        }
        for( Entity e : mf.simulation.controlPoints){
            sb.append("point " + e.getTransform().getTranslation().toStringSimple(" ") + "\n");
        }
        
        TextFrame.showText("Export Trans and points", sb.toString(), this);
    }
     
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addAnim;
    private javax.swing.JButton addStatus;
    private javax.swing.JList animationList;
    private javax.swing.JLabel currentFrameText;
    private javax.swing.JButton delAnim;
    private javax.swing.JButton delStatus;
    private javax.swing.JTextField durationText;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JButton nextButton;
    private javax.swing.JRadioButton pingpongWrap;
    private javax.swing.JSlider playSlider;
    private javax.swing.JToggleButton playToggle;
    private javax.swing.JButton prevButton;
    private javax.swing.JRadioButton repeatWrap;
    private javax.swing.JList statusList;
    private javax.swing.JButton stopButton;
    private javax.swing.JRadioButton stopWrap;
    private javax.swing.JTextField waitText;
    private javax.swing.ButtonGroup wraperGroup;
    // End of variables declaration//GEN-END:variables

    public void addKeyFrameNTimes() {
        final int nTimes = Parse.toInt( DialogUtils.getStringDialog(this, "Number of frames", "10") );
        for (int i = 0; i < nTimes; i++) {
            addKeyFrame();
        }
    }

   

}
