001        package com.croftsoft.apps.skipper;
002    
003        import java.awt.*;
004        import java.awt.event.*;
005        import java.io.*;
006        import java.util.*;
007        import java.util.logging.*;
008        import javax.imageio.*;
009        import javax.swing.*;
010    
011        import com.croftsoft.core.animation.ComponentAnimator;
012        import com.croftsoft.core.awt.image.ImageLib;
013        import com.croftsoft.core.lang.NullArgumentException;
014        import com.croftsoft.core.math.MathConstants;
015    
016        /***********************************************************************
017        * Skipper ComponentAnimator.
018        *
019        * Copyright 2007 David Wallace Croft.
020        * 
021        * @version
022        *   $Date: 2007/07/28 16:57:03 $ $Author: croft $
023        * @since
024        *   2006-12-19
025        * @author
026        *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
027        ***********************************************************************/
028    
029        public final class  SkipperAnimator
030          implements ComponentAnimator
031        ////////////////////////////////////////////////////////////////////////
032        ////////////////////////////////////////////////////////////////////////
033        {
034           
035        private static final String  CLASS_NAME
036          = SkipperAnimator.class.getName ( );
037    
038        //
039    
040        private final Logger         logger;
041    
042        private final SkipperConfig  skipperConfig;
043    
044        private final SkipperModel   skipperModel;
045    
046        private final Rectangle      componentBounds;
047    
048        private final Random         random;
049    
050        //
051    
052        private boolean  skip;
053    
054        private long     lastTimeNanos;
055    
056        private Image    image;
057    
058        private String   imageFilename;
059    
060        private int      imageIndex;
061    
062        ////////////////////////////////////////////////////////////////////////
063        // constructor methods
064        ////////////////////////////////////////////////////////////////////////
065    
066        /***********************************************************************
067        * Main constructor.
068        ***********************************************************************/
069        public  SkipperAnimator (
070          final SkipperConfig  skipperConfig,
071          final SkipperModel   skipperModel,
072          final JComponent     jComponent )
073        ////////////////////////////////////////////////////////////////////////
074        {
075          NullArgumentException.checkArgs (
076            this.skipperConfig = skipperConfig,
077            this.skipperModel  = skipperModel,
078            jComponent );
079    
080          logger = Logger.getLogger ( CLASS_NAME );
081    
082          componentBounds = new Rectangle ( );
083    
084          random = new Random ( );
085    
086          jComponent.setOpaque ( true );
087    
088          jComponent.setFont ( skipperConfig.getFont ( ) );
089    
090          jComponent.addKeyListener (
091            new KeyAdapter ( )
092            {
093              @Override
094              public void  keyPressed ( final KeyEvent  keyEvent )
095              {
096                final int  keyCode = keyEvent.getKeyCode ( );
097    
098                if ( keyCode == KeyEvent.VK_SPACE )
099                {
100                  logger.info ( "Spacebar pressed.  Skipping..." );
101    
102                  skip = true;
103                }
104              }
105            } );
106    
107          jComponent.requestFocus ( );
108    
109          update ( jComponent );       
110        }
111    
112        ////////////////////////////////////////////////////////////////////////
113        // interface ComponentAnimator methods
114        ////////////////////////////////////////////////////////////////////////
115    
116        public void  paint (
117          final JComponent  jComponent,
118          final Graphics2D  graphics2D )
119        ////////////////////////////////////////////////////////////////////////
120        {
121          try
122          {
123            jComponent.getBounds ( componentBounds );
124    
125            graphics2D.setColor ( skipperConfig.getBackgroundColor ( ) );
126    
127            graphics2D.fill ( componentBounds );
128    
129            if ( image != null )
130            {
131              final Rectangle  rectangle = ImageLib.shrinkToFitAndCenter (
132                image.getWidth  ( null ),
133                image.getHeight ( null ),
134                componentBounds.width,
135                componentBounds.height );
136    
137              graphics2D.drawImage (
138                image,
139                rectangle.x,
140                rectangle.y,
141                rectangle.width,
142                rectangle.height,
143                null );
144            }
145    
146            if ( imageFilename != null )
147            {
148              Boolean  displayingImageFilename
149                = skipperConfig.getDisplayingImageFilename ( );
150              
151              if ( displayingImageFilename == null )
152              {
153                displayingImageFilename
154                  = skipperConfig.getDefaultDisplayingImageFilename ( );
155                
156                skipperConfig.setDisplayingImageFilename (
157                  displayingImageFilename );
158              }
159              
160              if ( displayingImageFilename.booleanValue ( ) )
161              {
162                graphics2D.setColor ( skipperConfig.getForegroundColor ( ) );
163    
164                graphics2D.drawString ( imageFilename, 20, 20 );
165              }
166            }
167          }
168          catch ( final Exception  ex )
169          {
170            ex.printStackTrace ( );
171    
172            logger.throwing ( CLASS_NAME, "paint", ex );
173          }
174        }
175    
176        public void  update ( final JComponent  jComponent )
177        ////////////////////////////////////////////////////////////////////////
178        {
179          try
180          {
181            final long  currentTimeNanos = System.nanoTime ( );
182    
183            final long  deltaTimeNanos = currentTimeNanos - lastTimeNanos;
184    
185            long  displayTime = skipperConfig.getDisplayTime ( );
186    
187            if ( displayTime <= 0 )
188            {
189              displayTime = skipperConfig.getDefaultDisplayTime ( );
190    
191              skipperConfig.setDisplayTime ( displayTime );
192            }
193    
194            final long  displayTimeNanos
195              = displayTime * MathConstants.NANOSECONDS_PER_SECOND;
196            
197            final boolean  done = deltaTimeNanos >= displayTimeNanos; 
198    
199            if ( done || skip )
200            {
201              if ( skip )
202              {
203                skip = false;
204                
205                skipperModel.decreaseProbabilityOfSkipped ( imageIndex );
206    
207                skipperModel.divideEachProbabilityBySum ( );
208              }
209    
210              imageFilename = randomlyChooseSelection ( );
211    
212              if ( imageFilename != null )
213              {
214                final File  imageFile = new File ( imageFilename );
215    
216                image = ImageIO.read ( imageFile );
217    
218                lastTimeNanos = currentTimeNanos;             
219              }
220            }
221    
222            jComponent.paintImmediately ( componentBounds );
223          }
224          catch ( final Exception  ex )
225          {
226            ex.printStackTrace ( );
227    
228            logger.throwing ( CLASS_NAME, "update", ex );
229          }
230          catch ( final OutOfMemoryError  error )
231          {
232            System.err.println ( "Out of memory loading " + imageFilename );
233    
234            logger.throwing ( CLASS_NAME, "update", error );
235          }
236        }
237    
238        ////////////////////////////////////////////////////////////////////////
239        ////////////////////////////////////////////////////////////////////////
240    
241        private String  randomlyChooseSelection ( )
242        ////////////////////////////////////////////////////////////////////////
243        {
244          final String [ ]  selections = skipperModel.getSelections ( );
245    
246          if ( ( selections == null    )
247            || ( selections.length < 1 ) )
248          {
249            return null;
250          }
251    
252          final double [ ]  thresholds
253            = skipperModel.getCumulativeProbabilityThresholds ( );
254    
255          if ( ( thresholds == null    )
256            || ( thresholds.length < 1 ) )
257          {
258            return selections [ 0 ];
259          }
260    
261          final double  roll = random.nextDouble ( );
262    
263          imageIndex = 0;
264    
265          for ( int  i = 0; i < thresholds.length; i++ )
266          {
267            if ( roll < thresholds [ i ] )
268            {
269              break;
270            }
271    
272            imageIndex = i;
273          }
274    
275          logger.info ( "index = " + imageIndex + ", roll = " + roll );
276    
277          return selections [ imageIndex ];
278        }
279    
280        ////////////////////////////////////////////////////////////////////////
281        ////////////////////////////////////////////////////////////////////////
282        }