/** * Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP). * * This program 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. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package net.ctdp.rfdynhud.gamedata; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import net.ctdp.rfdynhud.editor.EditorPresets; import net.ctdp.rfdynhud.render.ImageTemplate; import net.ctdp.rfdynhud.util.RFDHLog; /** * Represents vehicle driving aids. * * @author Marvin Froehlich (CTDP) */ public abstract class DrivingAids { private long updateTimestamp = -1L; private long updateId = 0L; private boolean updatedInTimeScope = false; private final LiveGameData gameData; public static interface DrivingAidsUpdateListener extends LiveGameData.GameDataUpdateListener { public void onDrivingAidsUpdated( LiveGameData gameData, boolean isEditorMode ); } public static interface DrivingAidStateChangeListener extends DrivingAidsUpdateListener { public void onDrivingAidStateChanged( LiveGameData gameData, int aidIndex, int oldState, int newState ); } private DrivingAidsUpdateListener[] updateListeners = null; private boolean hasStateChangeListener = false; private int[] oldStates = null; private void updateHasStateChangeListener() { hasStateChangeListener = false; if ( updateListeners != null ) { for ( int i = 0; i < updateListeners.length; i++ ) { if ( updateListeners[i] instanceof DrivingAidStateChangeListener ) { hasStateChangeListener = true; break; } } } } public void registerListener( DrivingAidsUpdateListener l ) { if ( updateListeners == null ) { updateListeners = new DrivingAidsUpdateListener[] { l }; } else { for ( int i = 0; i < updateListeners.length; i++ ) { if ( updateListeners[i] == l ) return; } DrivingAidsUpdateListener[] tmp = new DrivingAidsUpdateListener[ updateListeners.length + 1 ]; System.arraycopy( updateListeners, 0, tmp, 0, updateListeners.length ); updateListeners = tmp; updateListeners[updateListeners.length - 1] = l; } updateHasStateChangeListener(); gameData.registerDataUpdateListener( l ); } public void unregisterListener( DrivingAidsUpdateListener l ) { if ( updateListeners == null ) return; int index = -1; for ( int i = 0; i < updateListeners.length; i++ ) { if ( updateListeners[i] == l ) { index = i; break; } } if ( index < 0 ) return; if ( updateListeners.length == 1 ) { updateListeners = null; updateHasStateChangeListener(); return; } DrivingAidsUpdateListener[] tmp = new DrivingAidsUpdateListener[ updateListeners.length - 1 ]; if ( index > 0 ) System.arraycopy( updateListeners, 0, tmp, 0, index ); if ( index < updateListeners.length - 1 ) System.arraycopy( updateListeners, index + 1, tmp, index, updateListeners.length - index - 1 ); updateListeners = tmp; updateHasStateChangeListener(); gameData.unregisterDataUpdateListener( l ); } /** * Gets the system nano time for the last data update. * * @return the system nano time for the last data update. */ public final long getUpdateTimestamp() { return ( updateTimestamp ); } /** * This is incremented every time the data is updated. * * @return the current update id. */ public final long getUpdateId() { return ( updateId ); } /** * Gets, whether these {@link DrivingAids} have at least been updated once. * * @return whether these {@link DrivingAids} have at least been updated once. */ public final boolean isValid() { return ( updateId > 0L ); } /** * Gets, whether the last update of these data has been done while in the cockpit. * @return whether the last update of these data has been done while in the cockpit. */ public final boolean isUpdatedInTimeScope() { return ( updatedInTimeScope ); } /** * @param userObject * @param timestamp */ protected void prepareDataUpdate( Object userObject, long timestamp ) { } /** * @param userObject (could be an instance of {@link EditorPresets}), if in editor mode * @param timestamp */ protected void onDataUpdatedImpl( Object userObject, long timestamp ) { } protected void applyEditorPresets( EditorPresets editorPresets ) { if ( editorPresets == null ) return; } /** * @param userObject (could be an instance of {@link EditorPresets}), if in editor mode * @param timestamp */ protected final void onDataUpdated( Object userObject, long timestamp ) { try { this.updatedInTimeScope = gameData.isInCockpit(); this.updateTimestamp = timestamp; this.updateId++; if ( userObject instanceof EditorPresets ) applyEditorPresets( (EditorPresets)userObject ); final int numAids = getNumAids(); if ( ( numAids > 0 ) && ( updateListeners != null ) ) { //boolean stateUpdates = gameData.isInCockpit() && hasStateChangeListener; boolean stateUpdates = hasStateChangeListener; for ( int i = 0; i < updateListeners.length; i++ ) { try { updateListeners[i].onDrivingAidsUpdated( gameData, userObject instanceof EditorPresets ); if ( ( oldStates != null ) && ( updateListeners[i] instanceof DrivingAidStateChangeListener ) ) { for ( int j = 0; j < numAids; j++ ) { int state = getAidState( j ); if ( state != oldStates[j] ) ( (DrivingAidStateChangeListener)updateListeners[i] ).onDrivingAidStateChanged( gameData, j, oldStates[j], state ); } } } catch ( Throwable t ) { RFDHLog.exception( t ); } } if ( stateUpdates ) { if ( ( oldStates == null ) || ( oldStates.length != numAids ) ) oldStates = new int[ numAids ]; for ( int i = 0; i < numAids; i++ ) { oldStates[i] = getAidState( i ); } } onDataUpdatedImpl( userObject, timestamp ); } } catch ( Throwable t ) { RFDHLog.exception( t ); } } protected abstract void updateDataImpl( Object userObject, long timestamp ); protected void updateData( Object userObject, long timestamp ) { prepareDataUpdate( userObject, timestamp ); updateDataImpl( userObject, timestamp ); onDataUpdated( userObject, timestamp ); } public abstract void readFromStream( InputStream in, EditorPresets editorPresets ) throws IOException; /** * Read default values. This is usually done in editor mode. * * @param editorPresets <code>null</code> in non editor mode */ public abstract void loadDefaultValues( EditorPresets editorPresets ); public abstract void writeToStream( OutputStream out ) throws IOException; /** * Gets the number of driving aids available in the current sim. * * @return the number of driving aids available in the current sim. */ public abstract int getNumAids(); /** * Gets the index into the array of aids for the traction control aid. * * @return the index into the array of aids for the traction control aid. */ public abstract int getAidIndexTractionControl(); /** * Gets the index into the array of aids for the anti lock brakes aid. * * @return the index into the array of aids for the anti lock brakes aid. */ public abstract int getAidIndexTractionAntiLockBrakes(); /** * Gets the index into the array of aids for the auto shift aid. * * @return the index into the array of aids for the auto shift aid. */ public abstract int getAidIndexAutoShift(); /** * Gets the index into the array of aids for the invulnerability mode. * * @return the index into the array of aids for the invulnerability mode. */ public abstract int getAidIndexInvulnerability(); /** * Gets the driving aid's name at the given index. * * @param index the index into the aids array * * @return the driving aid's name at the given index. * * @see #getNumAids() */ public abstract String getAidName( int index ); /** * Gets the requested driving aid's current state. 0 is usually disabled. * * @param index the index into the aids array * * @return the requested driving aid's current state. * * @see #getNumAids() * @see #isAidEnabled(int) */ public abstract int getAidState( int index ); /** * Checks, whether the requested driving aid is currently enabled. * * @param index the index into the aids array * * @return whether the requested driving aid is currently enabled. * * @see #getNumAids() * @see #getAidState(int) */ public boolean isAidEnabled( int index ) { return ( getAidState( index ) != 0 ); } /** * Gets a display name for the requested state. * * @param index the index into the aids array * @param state the requested state * * @return a display name for the requested state. * * @see #getNumAids() */ public abstract String getAidStateName( int index, int state ); /** * Gets a display name for the current state. * * @param index the index into the aids array * * @return a display name for the requested state. * * @see #getNumAids() */ public String getAidStateName( int index ) { return ( getAidStateName( index, getAidState( index ) ) ); } /** * Gets the minimum state for the requested driving aid (usually 0). * * @param index the index into the aids array * * @return the minimum state for the requested driving aid. * * @see #getNumAids() */ public abstract int getMinState( int index ); /** * Gets the maximum state for the requested driving aid (usually 0). * * @param index the index into the aids array * * @return the maximum state for the requested driving aid. * * @see #getNumAids() */ public abstract int getMaxState( int index ); /** * Gets the number of states for the requested driving aid (usually 0). * * @param index the index into the aids array * * @return the number of states for the requested driving aid. * * @see #getNumAids() */ public abstract int getNumStates( int index ); /** * Gets an {@link ImageTemplate} for the requested aid and state. * * @param index * @param state * * @return an {@link ImageTemplate} for the requested aid and state. * * @see #getNumAids() */ public abstract ImageTemplate getAidIcon( int index, int state ); /** * Gets an {@link ImageTemplate} for the requested aid and the current state. * * @param index * * @return an {@link ImageTemplate} for the requested aid and the current state. * * @see #getNumAids() */ public final ImageTemplate getAidIcon( int index ) { return ( getAidIcon( index, getAidState( index ) ) ); } public DrivingAids( LiveGameData gameData ) { this.gameData = gameData; } }