/usr/local/CPAN/Win32-CtrlGUI/Win32/CtrlGUI/State/atom.pm


###########################################################################
# Copyright 2000, 2001 Toby Everett.  All rights reserved.
#
# This file is distributed under the Artistic License. See
# http://www.ActiveState.com/corporate/artistic_license.htm or
# the license that comes with your perl distribution.
#
# For comments, questions, bugs or general interest, feel free to
# contact Toby Everett at teverett@alascom.att.com
##########################################################################
use Win32::CtrlGUI;
use Win32::CtrlGUI::State;

use strict;

package Win32::CtrlGUI::State::atom;
use vars qw($VERSION @ISA $action_error_handler);

@ISA = ('Win32::CtrlGUI::State');

$VERSION='0.30';

sub _new {
  my $class = shift;

  my $self = $class->SUPER::_new(@_);

  if (ref ($self->{criteria}) eq 'ARRAY') {
    $self->{criteria} = Win32::CtrlGUI::Criteria->new(@{$self->{criteria}});
  }

  return $self;
}

sub is_recognized {
  my $self = shift;

  if ($self->state =~ /^init|srch$/) {
    if ($self->state eq 'init') {
      $self->{state} = 'srch';
      $self->{timeout} and $self->{end_time} = Win32::GetTickCount()+$self->{timeout}*1000;
    }
    my $rcog = $self->{criteria}->is_recognized;
    if ($rcog) {
      if (ref $rcog) {
        $self->{rcog_win} = $rcog;
        $self->{name} and $Win32::CtrlGUI::Window::named_windows{$self->{name}} = $rcog;
      }

      $self->{state} = 'rcog';
      $self->{rcog_time} = Win32::GetTickCount();
      $self->debug_print(1, "Criteria $self->{criteria} met.");
    } else {
      if ($self->{end_time} && $self->{end_time} < Win32::GetTickCount()) {
        $self->debug_print(1, "Criteria $self->{criteria} was timed out.");
        $self->{state} = 'fail';
        return 1;
      }
      return 0;
    }
  } else {
    return 1;
  }
}

sub do_action_step {
  my $self = shift;

  if ($self->state eq 'rcog') {
    $self->{state} = 'actn';
    my $wait_time = $self->{rcog_time}/1000 + $self->action_delay - Win32::GetTickCount()/1000;
    $wait_time > 0 and $self->debug_print(1, sprintf("Looping for %0.3f seconds before executing action.", $wait_time));
  }
  $self->state eq 'actn' or return;

  if ($self->{rcog_time} + $self->action_delay * 1000 <= Win32::GetTickCount()) {
    my $coderef;
    if (ref $self->{action} eq 'CODE') {
      $self->debug_print(1, "Executing code action.");
      $coderef = $self->{action};
    } elsif ($self->{action}) {
      $self->debug_print(1, "Sending keys '$self->{action}'.");
      $coderef = sub { $_[0]->{rcog_win}->send_keys($_[0]->{action}); };
    } else {
      $self->debug_print(1, "No action.");
      $coderef = sub {};
    }

    eval {$coderef->($self);};
    if ($@) {
      $self->action_error_handler->($@);
    }

    $self->debug_print(1, "");
    $self->{state} = 'done';
  }
}

sub wait_action {
  my $self = shift;

  $self->state =~ /^actn|rcog$/ or return 0;

  my $wait_time = $self->{rcog_time} + $self->action_delay * 1000 - Win32::GetTickCount();
  if ($wait_time > 0) {
    $self->debug_print(1, "Sleeping for ".($wait_time/1000)." seconds before executing action.");
    Win32::Sleep($wait_time);
  }

  return $self->SUPER::wait_action();
}

sub reset {
  my $self = shift;

  $self->SUPER::reset;

  delete($self->{rcog_time});
  delete($self->{rcog_win});
  delete($self->{end_time});
  UNIVERSAL::isa($self->{criteria}, 'Win32::CtrlGUI::Criteria') and $self->{criteria}->reset;
}

sub action_error_handler {
  my $self = shift;

  ref($self->{action_error_handler}) eq 'CODE' and return $self->{action_error_handler};
  ref($action_error_handler) eq 'CODE' and return $action_error_handler;
  return sub { die $_[0]; };
}

sub stringify {
  my $self = shift;

  return join("\n", map {"$_ =>$self->{$_}"} grep {exists $self->{$_}} qw(criteria action name timeout));
}

sub tagged_stringify {
  my $self = shift;

  my @retval;

  push(@retval, ["criteria:\t", 'default']);
  push(@retval, $self->{criteria}->tagged_stringify);
  push(@retval, ["\n", 'default']);

  foreach my $i (qw(action name)) {
    exists $self->{$i} or next;
    push(@retval, ["$i:\t$self->{$i}\n", 'default']);
  }

  if ($self->{timeout}) {
    my $timeout;
    if ($self->{end_time}) {
      $timeout = ($self->{end_time}-Win32::GetTickCount())/1000;
      $timeout < 0 and $timeout = 0;
      $timeout = sprintf("%0.3f", $timeout);
    } else {
      $timeout = 'wait';
    }
    push(@retval, ["timeout => $timeout\n", 'default']);
  }

  chomp($retval[$#retval]->[0]);

  return @retval;
}

1;