<commit_before>/*
 * Info.java
 *
 * Created on September 28, 2007, 7:29 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 *
 *
 *Copyright September 28, 2007 <NAME>, Inst. of Neuroinformatics, UNI-ETH Zurich
 */

package ch.unizh.ini.caviar.eventprocessing.filter;

import ch.unizh.ini.caviar.aemonitor.AEConstants;
import ch.unizh.ini.caviar.chip.*;
import ch.unizh.ini.caviar.event.EventPacket;
import ch.unizh.ini.caviar.eventio.AEDataFile;
import ch.unizh.ini.caviar.eventio.AEFileInputStream;
import ch.unizh.ini.caviar.eventio.AEInputStreamInterface;
import ch.unizh.ini.caviar.eventprocessing.*;
import ch.unizh.ini.caviar.graphics.AEPlayerInterface;
import ch.unizh.ini.caviar.graphics.AEViewer;
import ch.unizh.ini.caviar.graphics.FrameAnnotater;
import com.sun.opengl.util.*;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.io.File;
import java.text.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.media.opengl.*;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.*;

/**
 * Annotates the rendered data stream canvas
 with additional information like a
 clock with absolute time, a bar showing instantaneous activity rate,
 a graph showing historical activity over the file, etc.
 These features are enabled by flags of the filter.
 * @author tobi
 */
public class Info extends EventFilter2D implements FrameAnnotater, PropertyChangeListener {
    
    DateFormat timeFormat=DateFormat.getTimeInstance();
    DateFormat dateFormat=DateFormat.getDateInstance();
    Date dateInstance=new Date();
    Calendar calendar=Calendar.getInstance();
    File lastFile=null;
    
    private boolean analogClock=getPrefs().getBoolean("Into.analogClock",true);
    {setPropertyTooltip("analogClock","show normal circular clock");}
    private boolean digitalClock=getPrefs().getBoolean("Into.digitalClock",true);
    {setPropertyTooltip("digitalClock","show digital clock");}
    private boolean date=getPrefs().getBoolean("Into.date",true);
    {setPropertyTooltip("date","show date");}
    private boolean absoluteTime=getPrefs().getBoolean("Info.absoluteTime",true);
    {setPropertyTooltip("absoluteTime","enable to show absolute time, disable to show timestmp time (usually relative to start of recording");}
    
    private long dataFileTimestampStartTimeMs=0;
    private long wrappingCorrectionMs=0;
    private long absoluteStartTimeMs=0;
    private long relativeTimeInFileMs=0;
    private boolean addedViewerPropertyChangeListener=false; // need flag because viewer doesn't exist on creation
    
    /** Creates a new instance of Info for the chip
     @param chip the chip object
     */
    public Info(AEChip chip) {
        super(chip);
        calendar.setLenient(true); // speed up calendar
    }
    
    /** handles tricky property changes coming from AEViewer and AEFileInputStream */
    public void propertyChange(PropertyChangeEvent evt) {
        if(evt.getSource() instanceof AEFileInputStream){
            if(evt.getPropertyName().equals("rewind")){
                log.info("rewind PropertyChangeEvent received by "+this+" from "+evt.getSource());
                wrappingCorrectionMs=0;
            }else if(evt.getPropertyName().equals("wrappedTime")){
                wrappingCorrectionMs+=(long)(1L<<32L)/1000; // fixme
            }else if(evt.getPropertyName().equals("init")){
                AEFileInputStream fis=(AEFileInputStream)(evt.getSource());
            }
        }else if(evt.getSource() instanceof AEViewer){
            if(evt.getPropertyName().equals("fileopen")){ // we don't get this on initial fileopen because this filter has not yet been run so we have not added ourselves to the viewer
                getAbsoluteStartingTimeMsFromFile();
            }
        }
    }
    
    private void getAbsoluteStartingTimeMsFromFile(){
        AEPlayerInterface player=chip.getAeViewer().getAePlayer();
        if(player!=null){
            AEFileInputStream in=(AEFileInputStream)(player.getAEInputStream());
            if(in!=null){
                in.getSupport().addPropertyChangeListener(this);
                dataFileTimestampStartTimeMs=in.getFirstTimestamp();
                log.info("added ourselves for PropertyChangeEvents from "+in);
                absoluteStartTimeMs=in.getAbsoluteStartingTimeMs();
            }
        }
    }
    
    public EventPacket<?> filterPacket(EventPacket<?> in) {
        if(!addedViewerPropertyChangeListener){
            chip.getAeViewer().getSupport().addPropertyChangeListener(this);
            addedViewerPropertyChangeListener=true;
            getAbsoluteStartingTimeMsFromFile();
        }
        if(in!=null && in.getSize()>0){
            relativeTimeInFileMs=(in.getLastTimestamp()-dataFileTimestampStartTimeMs)/1000;
        }
        return in;
    }
    
    public Object getFilterState() {
        return null;
    }
    
    public void resetFilter() {
    }
    
    public void initFilter() {
    }
    
    public void annotate(float[][][] frame) {
    }
    
    public void annotate(Graphics2D g) {
    }
    
    GLU glu=null;
    GLUquadric wheelQuad;
    
    public void annotate(GLAutoDrawable drawable) {
        if(!isAnnotationEnabled()) return;
        GL gl=drawable.getGL();
        long t=0;
        if(chip.getAeViewer().getPlayMode()==AEViewer.PlayMode.LIVE) {
            t=System.currentTimeMillis();
        }else{
            t=relativeTimeInFileMs+wrappingCorrectionMs;
            if(absoluteTime) t+=absoluteStartTimeMs;
        }
        drawClock(gl,t);
    }
    
    
    private void drawClock(GL gl, long t){
        final int radius=20, hourLen=10, minLen=19, secLen=7;
        calendar.setTimeInMillis(t);
        
        gl.glColor3f(1,1,1);
        if(analogClock){
            // draw clock circle
            if(glu==null) glu=new GLU();
            if(wheelQuad==null) wheelQuad = glu.gluNewQuadric();
            gl.glPushMatrix();
            {
                gl.glTranslatef(radius+2, radius+6,0); // clock center
                glu.gluQuadricDrawStyle(wheelQuad,GLU.GLU_FILL);
                glu.gluDisk(wheelQuad,radius,radius+0.5f,24,1);
                
                // draw hour, minute, second hands
                // each hand has x,y components related to periodicity of clock and time
                
                gl.glColor3f(1,1,1);
                
                // second hand
                gl.glLineWidth(2f);
                gl.glBegin(GL.GL_LINES);
                gl.glVertex2f(0,0);
                double a=2*Math.PI*calendar.get(Calendar.SECOND)/60;
                float x=secLen*(float)Math.sin(a);
                float y=secLen*(float)Math.cos(a);
                gl.glVertex2f(x,y);
                gl.glEnd();
                
                // minute hand
                gl.glLineWidth(4f);
                gl.glBegin(GL.GL_LINES);
                gl.glVertex2f(0,0);
                int minute=calendar.get(Calendar.MINUTE);
                a=2*Math.PI*minute/60;
                x=minLen*(float)Math.sin(a);
                y=minLen*(float)Math.cos(a); // y= + when min=0, pointing at noon/midnight on clock<commit_msg>Info now shows milliseconds hand and milliseconds value in digital clock. This information can be useful for timing motor responses, e.g. in Goalie.<commit_after>/*
 * Info.java
 *
 * Created on September 28, 2007, 7:29 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 *
 *
 *Copyright September 28, 2007 <NAME>, Inst. of Neuroinformatics, UNI-ETH Zurich
 */

package ch.unizh.ini.caviar.eventprocessing.filter;

import ch.unizh.ini.caviar.aemonitor.AEConstants;
import ch.unizh.ini.caviar.chip.*;
import ch.unizh.ini.caviar.event.EventPacket;
import ch.unizh.ini.caviar.eventio.AEDataFile;
import ch.unizh.ini.caviar.eventio.AEFileInputStream;
import ch.unizh.ini.caviar.eventio.AEInputStreamInterface;
import ch.unizh.ini.caviar.eventprocessing.*;
import ch.unizh.ini.caviar.graphics.AEPlayerInterface;
import ch.unizh.ini.caviar.graphics.AEViewer;
import ch.unizh.ini.caviar.graphics.FrameAnnotater;
import com.sun.opengl.util.*;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.io.File;
import java.text.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.media.opengl.*;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.*;

/**
 * Annotates the rendered data stream canvas
 with additional information like a
 clock with absolute time, a bar showing instantaneous activity rate,
 a graph showing historical activity over the file, etc.
 These features are enabled by flags of the filter.
 * @author tobi
 */
public class Info extends EventFilter2D implements FrameAnnotater, PropertyChangeListener {
    
    DateFormat timeFormat=new SimpleDateFormat("k:mm:ss.S"); //DateFormat.getTimeInstance();
    DateFormat dateFormat=DateFormat.getDateInstance();
    Date dateInstance=new Date();
    Calendar calendar=Calendar.getInstance();
    File lastFile=null;
    
    private boolean analogClock=getPrefs().getBoolean("Into.analogClock",true);
    {setPropertyTooltip("analogClock","show normal circular clock");}
    private boolean digitalClock=getPrefs().getBoolean("Into.digitalClock",true);
    {setPropertyTooltip("digitalClock","show digital clock");}
    private boolean date=getPrefs().getBoolean("Into.date",true);
    {setPropertyTooltip("date","show date");}
    private boolean absoluteTime=getPrefs().getBoolean("Info.absoluteTime",true);
    {setPropertyTooltip("absoluteTime","enable to show absolute time, disable to show timestmp time (usually relative to start of recording");}
    
    private long dataFileTimestampStartTimeMs=0;
    private long wrappingCorrectionMs=0;
    private long absoluteStartTimeMs=0;
    private long relativeTimeInFileMs=0;
    private boolean addedViewerPropertyChangeListener=false; // need flag because viewer doesn't exist on creation
    
    /** Creates a new instance of Info for the chip
     @param chip the chip object
     */
    public Info(AEChip chip) {
        super(chip);
        calendar.setLenient(true); // speed up calendar
    }
    
    /** handles tricky property changes coming from AEViewer and AEFileInputStream */
    public void propertyChange(PropertyChangeEvent evt) {
        if(evt.getSource() instanceof AEFileInputStream){
            if(evt.getPropertyName().equals("rewind")){
                log.info("rewind PropertyChangeEvent received by "+this+" from "+evt.getSource());
                wrappingCorrectionMs=0;
            }else if(evt.getPropertyName().equals("wrappedTime")){
                wrappingCorrectionMs+=(long)(1L<<32L)/1000; // fixme
            }else if(evt.getPropertyName().equals("init")){
                AEFileInputStream fis=(AEFileInputStream)(evt.getSource());
            }
        }else if(evt.getSource() instanceof AEViewer){
            if(evt.getPropertyName().equals("fileopen")){ // we don't get this on initial fileopen because this filter has not yet been run so we have not added ourselves to the viewer
                getAbsoluteStartingTimeMsFromFile();
            }
        }
    }
    
    private void getAbsoluteStartingTimeMsFromFile(){
        AEPlayerInterface player=chip.getAeViewer().getAePlayer();
        if(player!=null){
            AEFileInputStream in=(AEFileInputStream)(player.getAEInputStream());
            if(in!=null){
                in.getSupport().addPropertyChangeListener(this);
                dataFileTimestampStartTimeMs=in.getFirstTimestamp();
                log.info("added ourselves for PropertyChangeEvents from "+in);
                absoluteStartTimeMs=in.getAbsoluteStartingTimeMs();
            }
        }
    }
    
    public EventPacket<?> filterPacket(EventPacket<?> in) {
        if(!addedViewerPropertyChangeListener){
            chip.getAeViewer().getSupport().addPropertyChangeListener(this);
            addedViewerPropertyChangeListener=true;
            getAbsoluteStartingTimeMsFromFile();
        }
        if(in!=null && in.getSize()>0){
            relativeTimeInFileMs=(in.getLastTimestamp()-dataFileTimestampStartTimeMs)/1000;
        }
        return in;
    }
    
    public Object getFilterState() {
        return null;
    }
    
    public void resetFilter() {
    }
    
    public void initFilter() {
    }
    
    public void annotate(float[][][] frame) {
    }
    
    public void annotate(Graphics2D g) {
    }
    
    GLU glu=null;
    GLUquadric wheelQuad;
    
    public void annotate(GLAutoDrawable drawable) {
        if(!isAnnotationEnabled()) return;
        GL gl=drawable.getGL();
        long t=0;
        if(chip.getAeViewer().getPlayMode()==AEViewer.PlayMode.LIVE) {
            t=System.currentTimeMillis();
        }else{
            t=relativeTimeInFileMs+wrappingCorrectionMs;
            if(absoluteTime) t+=absoluteStartTimeMs;
        }
        drawClock(gl,t);
    }
    
    
    private void drawClock(GL gl, long t){
        final int radius=20, hourLen=10, minLen=18, secLen=7, msLen=19;
        calendar.setTimeInMillis(t);
        
        gl.glColor3f(1,1,1);
        if(analogClock){
            // draw clock circle
            if(glu==null) glu=new GLU();
            if(wheelQuad==null) wheelQuad = glu.gluNewQuadric();
            gl.glPushMatrix();
            {
                gl.glTranslatef(radius+2, radius+6,0); // clock center
                glu.gluQuadricDrawStyle(wheelQuad,GLU.GLU_FILL);
                glu.gluDisk(wheelQuad,radius,radius+0.5f,24,1);
                
                // draw hour, minute, second hands
                // each hand has x,y components related to periodicity of clock and time
                
                gl.glColor3f(1,1,1);
                
                // ms hand
                gl.glLineWidth(1f);
                gl.glBegin(GL.GL_LINES);
                gl.glVertex2f(0,0);
                double a=2*Math.PI*calendar.get(Calendar.MILLISECOND)/1000;
                float x=msLen*(float)Math.sin(a);
                float y=msLen*(float)Math.cos(a);
                gl.glVertex2f(x,y);
                gl.glEnd();
                
                // second hand
                gl.glLineWidth(2f);
                gl.glBegin(GL.GL_LINES);
                gl.glVertex2f(0,0);
                a=2*Math.PI*calendar.get(Calendar.SECOND)/60;
                x=secLen*(float)Math.sin(a);
                y=secLen*(float)Math.cos(a);
                gl.glVertex2f(x,y);
                gl.glEnd();
                
                // minute hand
                gl.glLineWidth(4f);
                gl.glBegin(GL.GL_LINES);
                gl.glVertex2f(0,0);
                int minute=calendar.get(Calendar.MINUTE);
                a=2*Math.PI*minute/60;
                x=minLen*(float)Math.sin(a);
                y=minLen*(float)Math.cos(a); // y= + when min=0, pointing at noon/midnight on clock
{'fraction_non_alphanumeric': 0.10881578947368421, 'fraction_numerical': 0.010657894736842106, 'mean_word_length': 2.5674724243135416, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3136225', 'n_tokens_mistral': 4512, 'n_tokens_neox': 4353, 'n_words': 906}