/**
* Copyright 2014 Comcast Cable Communications Management, LLC
*
* This file is part of CATS.
*
* CATS 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 3 of the License, or
* (at your option) any later version.
*
* CATS 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 CATS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.comcast.cats.vision.panel.remote;
import static com.comcast.cats.RemoteCommand.A;
import static com.comcast.cats.RemoteCommand.B;
import static com.comcast.cats.RemoteCommand.C;
import static com.comcast.cats.RemoteCommand.CHDN;
import static com.comcast.cats.RemoteCommand.CHUP;
import static com.comcast.cats.RemoteCommand.DELETE;
import static com.comcast.cats.RemoteCommand.DOWN;
import static com.comcast.cats.RemoteCommand.EIGHT;
import static com.comcast.cats.RemoteCommand.EXIT;
import static com.comcast.cats.RemoteCommand.FAV;
import static com.comcast.cats.RemoteCommand.FF;
import static com.comcast.cats.RemoteCommand.FIVE;
import static com.comcast.cats.RemoteCommand.FOUR;
import static com.comcast.cats.RemoteCommand.GUIDE;
import static com.comcast.cats.RemoteCommand.HDZOOM;
import static com.comcast.cats.RemoteCommand.HELP;
import static com.comcast.cats.RemoteCommand.INFO;
import static com.comcast.cats.RemoteCommand.LANGUAGE;
import static com.comcast.cats.RemoteCommand.LAST;
import static com.comcast.cats.RemoteCommand.LEFT;
import static com.comcast.cats.RemoteCommand.LIVE;
import static com.comcast.cats.RemoteCommand.MENU;
import static com.comcast.cats.RemoteCommand.MUTE;
import static com.comcast.cats.RemoteCommand.MYDVR;
import static com.comcast.cats.RemoteCommand.NINE;
import static com.comcast.cats.RemoteCommand.ONDEMAND;
import static com.comcast.cats.RemoteCommand.ONE;
import static com.comcast.cats.RemoteCommand.PAUSE;
import static com.comcast.cats.RemoteCommand.PGDN;
import static com.comcast.cats.RemoteCommand.PGUP;
import static com.comcast.cats.RemoteCommand.PIPCHDN;
import static com.comcast.cats.RemoteCommand.PIPCHUP;
import static com.comcast.cats.RemoteCommand.PIPMOVE;
import static com.comcast.cats.RemoteCommand.PIPONOFF;
import static com.comcast.cats.RemoteCommand.PIPSWAP;
import static com.comcast.cats.RemoteCommand.PLAY;
import static com.comcast.cats.RemoteCommand.POUND;
import static com.comcast.cats.RemoteCommand.POWER;
import static com.comcast.cats.RemoteCommand.REC;
import static com.comcast.cats.RemoteCommand.REPLAY;
import static com.comcast.cats.RemoteCommand.REW;
import static com.comcast.cats.RemoteCommand.RIGHT;
import static com.comcast.cats.RemoteCommand.SELECT;
import static com.comcast.cats.RemoteCommand.SEVEN;
import static com.comcast.cats.RemoteCommand.SIX;
import static com.comcast.cats.RemoteCommand.SKIPFWD;
import static com.comcast.cats.RemoteCommand.STAR;
import static com.comcast.cats.RemoteCommand.STOP;
import static com.comcast.cats.RemoteCommand.THREE;
import static com.comcast.cats.RemoteCommand.TV_VCR;
import static com.comcast.cats.RemoteCommand.TWO;
import static com.comcast.cats.RemoteCommand.UP;
import static com.comcast.cats.RemoteCommand.VOLDN;
import static com.comcast.cats.RemoteCommand.VOLUP;
import static com.comcast.cats.RemoteCommand.ZERO;
import static com.comcast.cats.vision.util.CatsVisionConstants.PLEASE_ALLOCATE_MSG;
import static com.comcast.cats.vision.util.CatsVisionConstants.DIRECT_TUNE_TEXT_FIELD_NAME;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JTextField;
import org.apache.log4j.Logger;
import com.comcast.cats.RemoteCommand;
import com.comcast.cats.RemoteLayout;
import com.comcast.cats.Settop;
import com.comcast.cats.event.CatsEventDispatcher;
import com.comcast.cats.provider.RemoteProvider;
import com.comcast.cats.vision.event.ActionType;
import com.comcast.cats.vision.event.RemoteEvent;
import com.comcast.cats.vision.panel.videogrid.model.GridDataModel;
import com.comcast.cats.vision.util.CatsVisionUtils;
/**
* This class is the controller for the remote panel in cats vision.
*
* @author bemman01c
*
*/
@Named
public class RemoteController extends AbstractAction implements MouseListener, FocusListener
{
/**
*
*/
private static final long serialVersionUID = -6999100610171185232L;
private static final Logger logger = Logger.getLogger( RemoteController.class );
public static long DELAY = 500;
public static long DIVISION_FACTOR = 100;
Settop settop;
/**
* Place holder for future development This variable will not be use. We
* will only be using the CatsEventDispatcher.
*/
private RemoteProvider remoteProvider;
/**
* Model in MVC for multi grid view.
*/
private GridDataModel gridDataModel;
/**
* The reference to the CATSEvent dispatcher. This is responsible for
* dispatching an event to all the boxes in a grid.
*/
private CatsEventDispatcher catsEventDispatcher;
/**
* Direct tune controller handles the direct tune actions
*/
DirectTuneController directTuneController;
/**
* Reference to the View
*/
RemoteControlView remoteControlView;
private boolean keyboardShortcutsEnabled = true;
private long mousePressed = 0;
private long mouseReleased = 0;
/**
* Construct a Remote taking the CatsEventDispatcher as its parameter
*
* @param catsEventDispatcher
* @param model
*/
@Inject
public RemoteController( CatsEventDispatcher catsEventDispatcher, GridDataModel model )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Creating RemoteController with catsEventDispatcher and gridDataModel" );
}
this.catsEventDispatcher = catsEventDispatcher;
this.remoteProvider = null;
this.gridDataModel = model;
List< RemoteLayout > keys = getKeysLayout();
remoteControlView = new RemoteControlView( this, "RemoteControlPanel", keys );
initDirectTunePanel();
remoteControlView.performRemoteButtonLayout();
}
private void initDirectTunePanel()
{
directTuneController = new DirectTuneController( catsEventDispatcher, ( FocusListener ) this, gridDataModel);
remoteControlView.addDirectTunePanel( directTuneController.getDirectTunePanel() );
}
public RemoteControlView getRemote()
{
return remoteControlView;
}
@Override
public void actionPerformed( ActionEvent e )
{
if ( keyboardShortcutsEnabled )
{
Object obj = e.getSource();
if ( obj instanceof RemoteButton )
{
keyPress( ( RemoteButton ) obj );
}
}
}
protected void keyPress( RemoteButton remoteButton )
{
logger.debug( "Clicked GridRemotePanel Remote button - " + remoteButton.getRemoteCommand().toString() );
Set< Settop > allocatedAndSelectedSettops = gridDataModel.getAllocatedAndSelectedSettops();
if ( ( allocatedAndSelectedSettops != null ) && !( allocatedAndSelectedSettops.isEmpty() ) )
{
long mouseDuration = mouseReleased - mousePressed;
int count = 0;
if ( mouseDuration > DELAY )
{
/*
* There are about 10 pressKeys per second and 1000 ms/second,
* so divide by 100 for a good pressKey number.
*/
count = new Long( mouseDuration / DIVISION_FACTOR ).intValue();
if ( logger.isDebugEnabled() )
{
logger.debug( "Calling pressKeyAndHold. Count for pressAndHold = " + count );
}
catsEventDispatcher.sendCatsEvent( new RemoteEvent( ActionType.PRESS_AND_HOLD, RemoteCommand
.parse( remoteButton.getText() ), "RemoteController", this, count ) );
}
else
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Calling pressKey" );
}
catsEventDispatcher.sendCatsEvent( new RemoteEvent( ActionType.PRESS, RemoteCommand.parse( remoteButton
.getText() ), "RemoteController", this, count ) );
}
mousePressed = 0;
mouseReleased = 0;
}
else
{
CatsVisionUtils.showWarning( "Unable to perform the operation", PLEASE_ALLOCATE_MSG + " Remote" );
}
}
@Override
public void mouseClicked( MouseEvent mouseEvent )
{
Object obj = mouseEvent.getSource();
if ( obj instanceof RemoteButton )
{
keyPress( ( RemoteButton ) obj );
}
}
@Override
public void mousePressed( MouseEvent e )
{
mousePressed = System.currentTimeMillis();
Point mousePosition = getMouseClickedLocation( e );
JButton button = ( JButton ) e.getSource();
remoteControlView.showPressAndHoldPanel( mousePosition, button );
}
@Override
public void mouseReleased( MouseEvent e )
{
mouseReleased = System.currentTimeMillis();
remoteControlView.hidePressAndHoldPanel();
}
@Override
public void mouseEntered( MouseEvent e )
{
// TODO Auto-generated method stub
}
@Override
public void mouseExited( MouseEvent e )
{
// TODO Auto-generated method stub
}
private List< RemoteLayout > getKeysLayout()
{
List< RemoteLayout > keys = null;
try
{
keys = remoteProvider.getValidKeys();
}
catch ( Exception e )
{
logger.info( "getValidKeys did not return a value, using defaults" + e );
}
if ( keys == null || keys.size() == 0 )
{
logger.debug( "Using default key layout." );
keys = getDefaultKeyLayout();
}
return keys;
}
/**
* Provide a default key layout if one is unable to be retrieved from the
* server.
*/
private List< RemoteLayout > getDefaultKeyLayout()
{
List< RemoteLayout > keys = new ArrayList< RemoteLayout >();
Integer panel = 0;
Integer row = 0;
keys.add( createRemoteLayout( row, 1, panel, ONDEMAND ) );
keys.add( createRemoteLayout( row, 2, panel, POWER ) );
panel++;
row = 0;
keys.add( createRemoteLayout( row, 0, panel, REW ) );
keys.add( createRemoteLayout( row, 1, panel, PLAY ) );
keys.add( createRemoteLayout( row, 2, panel, FF ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, STOP ) );
keys.add( createRemoteLayout( row, 1, panel, PAUSE ) );
keys.add( createRemoteLayout( row, 2, panel, REC ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, LAST ) );
keys.add( createRemoteLayout( row, 1, panel, MYDVR ) );
keys.add( createRemoteLayout( row, 2, panel, LIVE ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, SKIPFWD ) );
keys.add( createRemoteLayout( row, 1, panel, REPLAY ) );
row = 0;
panel++;
keys.add( createRemoteLayout( row, 0, panel, A ) );
keys.add( createRemoteLayout( row, 1, panel, B ) );
keys.add( createRemoteLayout( row, 2, panel, C ) );
row = 0;
panel++;
keys.add( createRemoteLayout( row, 0, panel, PGUP ) );
keys.add( createRemoteLayout( row, 1, panel, UP ) );
keys.add( createRemoteLayout( row, 2, panel, PGDN ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, LEFT ) );
keys.add( createRemoteLayout( row, 1, panel, SELECT ) );
keys.add( createRemoteLayout( row, 2, panel, RIGHT ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, LANGUAGE ) );
keys.add( createRemoteLayout( row, 1, panel, DOWN ) );
row = 0;
panel++;
keys.add( createRemoteLayout( row, 0, panel, GUIDE ) );
keys.add( createRemoteLayout( row, 1, panel, INFO ) );
keys.add( createRemoteLayout( row, 2, panel, MENU ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, EXIT ) );
keys.add( createRemoteLayout( row, 1, panel, HELP ) );
keys.add( createRemoteLayout( row, 2, panel, LAST ) );
row = 0;
panel++;
keys.add( createRemoteLayout( row, 0, panel, VOLUP ) );
keys.add( createRemoteLayout( row, 1, panel, MUTE ) );
keys.add( createRemoteLayout( row, 2, panel, CHUP ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, VOLDN ) );
keys.add( createRemoteLayout( row, 1, panel, FAV ) );
keys.add( createRemoteLayout( row, 2, panel, CHDN ) );
row = 0;
panel++;
keys.add( createRemoteLayout( row, 0, panel, ONE ) );
keys.add( createRemoteLayout( row, 1, panel, TWO ) );
keys.add( createRemoteLayout( row, 2, panel, THREE ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, FOUR ) );
keys.add( createRemoteLayout( row, 1, panel, FIVE ) );
keys.add( createRemoteLayout( row, 2, panel, SIX ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, SEVEN ) );
keys.add( createRemoteLayout( row, 1, panel, EIGHT ) );
keys.add( createRemoteLayout( row, 2, panel, NINE ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, STAR ) );
keys.add( createRemoteLayout( row, 1, panel, ZERO ) );
keys.add( createRemoteLayout( row, 2, panel, POUND ) );
row = 0;
panel++;
keys.add( createRemoteLayout( row, 0, panel, TV_VCR ) );
keys.add( createRemoteLayout( row, 1, panel, DELETE ) );
keys.add( createRemoteLayout( row, 2, panel, HDZOOM ) );
row++;
keys.add( createRemoteLayout( row, 0, panel, PIPONOFF ) );
keys.add( createRemoteLayout( row, 1, panel, PIPSWAP ) );
keys.add( createRemoteLayout( row, 2, panel, PIPMOVE ) );
row++;
keys.add( createRemoteLayout( row, 1, panel, PIPCHUP ) );
keys.add( createRemoteLayout( row, 2, panel, PIPCHDN ) );
return keys;
}
private RemoteLayout createRemoteLayout( Integer row, Integer col, Integer panel, RemoteCommand c )
{
RemoteLayout layout = new RemoteLayout( row, col, panel, c );
return layout;
}
/**
* To enable and disable keyboard shortcuts
*
* @param value
*/
public void enableKeyboardShortcuts( boolean value )
{
keyboardShortcutsEnabled = value;
}
public boolean isKeyboardShortcutsEnabled()
{
return keyboardShortcutsEnabled;
}
/**
* Obtain the pixel point where the mouse clicked occurred w.r.t RemotePanel
*
* @param e
* - the Mouse Event.
* @return - the mouse clicked point
*/
protected Point getMouseClickedLocation( MouseEvent e )
{
// this for remote panel button presses only.
JButton button = ( JButton ) e.getSource();
int x = e.getX();
int y = e.getY();
Component parent = button;
// add the x, y of all the parents till RemotePanel to get pixel
// position
// w.r.t to RemotePanel
while ( !( parent instanceof RemoteControlView ) )
{
x += parent.getX();
y += parent.getY();
parent = parent.getParent();
}
return new Point( x, y );
}
/**
* Updates the remote layout based on the remote provider
*
* @param remoteProvider
*/
public void updateRemoteLayout( RemoteProvider remoteProvider )
{
this.remoteProvider = remoteProvider;
List< RemoteLayout > keys = getKeysLayout();
remoteControlView = new RemoteControlView( this, "RemoteControlPanel", keys );
remoteControlView.setRemoteLayout( keys );
remoteControlView.performRemoteButtonLayout();
}
@Override
public void focusGained( FocusEvent fevent )
{
validateFocusState( fevent, true );
}
@Override
public void focusLost( FocusEvent fevent )
{
validateFocusState( fevent, false );
}
/**
* Listens to focus change events on the text area inside the Direct tune
* panel and then toggles the keyboard short cut state.If focus state is
* true disable the key board shortcut and vice versa
*
* @param fevent
* @param focusState
*/
private void validateFocusState( FocusEvent fevent, boolean focusState )
{
Object source = fevent.getSource();
if ( !( source instanceof JTextField ) )
{
return;
}
JTextField textField = ( JTextField ) source;
if ( textField.getName().equals( DIRECT_TUNE_TEXT_FIELD_NAME ) )
{
enableKeyboardShortcuts( !focusState );
}
}
}