Package net.sourceforge.scrumbot

Source Code of net.sourceforge.scrumbot.ScrumBot

package net.sourceforge.scrumbot;

import org.jibble.pircbot.*;

import java.util.Collection;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Calendar;

public class ScrumBot extends PircBot implements Runnable {

    public enum State { IDLE, WAITING_ATTENDEES, WAITING_REPORTS };

    private State state = State.IDLE;
    private Calendar previousStateChange = Calendar.getInstance();
   
    // list of members that were active in the previous scrum
    private List<Member> previousMembers = new LinkedList();
    // list of members that are supposed to say something in this scrum
    private List<Member> scrumMembers = new LinkedList();
   
    // map of nick -> Member
    private Map<String, Member> members = new HashMap();

    private Member activeMember;

    // TODO: get rid of this and actually have a list of Channel -objects in a map with all of the private members
    // of this object so that all channels can have their own scrums.
    private String channel;

    public ScrumBot() {
        this.setName("ScrumBot");

  new Thread(this).start();
    }

    public void onJoin(String channel, String sender, String login, String hostname)
    {
  if( !sender.equals( getName() ) )
      {
    //sendMessage( channel, "Hi, " + sender + "! My name is " + getName() + ", and I'm the scrum bot here!" );
    op( channel, sender );
      }
    }

    public void onNickChange(String oldNick, String login, String hostname, String newNick)
    {
  // TODO
    }

    public void onMessage(String channel, String sender, String login, String hostname, String msg)
    {
  this.channel = channel;

  Member m = getMember(channel, sender, login, hostname);
  String message = msg.toLowerCase();

  if( message.startsWith( getName().toLowerCase() ": start" ) )
      {
    startScrum(channel);
      }
  if( message.startsWith( getName().toLowerCase() + ": next" ) )
      {
          if( state != State.WAITING_REPORTS ) startReporting(channel);
    else nextMember(channel);
      }
  if( message.startsWith( getName().toLowerCase() + ": reset" ) )
      {
    if( getState(channel) != State.IDLE ) endScrum(channel);
    scrumMembers = new LinkedList();
    activeMember = null;
    members = new HashMap();
    previousMembers = new LinkedList();
      }
  if( message.contains( getName().toLowerCase() + ": quit" ) )
      {
    quitServer( sender + " told me to quit" );
      }
  if( message.contains( getName().toLowerCase() + ": help" ) )
      {
    sendMessage( sender, "I'll notify everyone when scrum starts. After that you have 30 seconds time to say \"hi\" to be included in scrum." );
    sendMessage( sender, "I'll then ask everyone in reverse order to report. You should answer the following questions:" );
    sendMessage( sender, "  1. What you did since last scrum?" );
    sendMessage( sender, "  2. What you're going to do before next scrum?" );
    sendMessage( sender, "  3. Are there impediments or obstacles that slow/stop your work?" );
    sendMessage( sender, "  When you're done include \"done.\" in your report." );
    sendMessage( sender, "After all are done, I'll end the daily scrum. The next scrum will be held the next day." );
    sendMessage( sender, "I understand the following commands: \"start\" (to start scrum), \"next\" (to skip to next reporter), \"reset\" (to" );
    sendMessage( sender, "reset my internal state), \"help\" (this help) and \"quit\" (makes me quit)." );
    sendMessage( sender, "Please note that you really should not need to use those commands. Use them only if there's real trouble." );
      }

  if( message.startsWith( "hi" ) )
      {
    if( !scrumMembers.contains(m) ) scrumMembers.add(m);

    if( state == State.WAITING_REPORTS )
        {
      sendMessage( channel, m.getName() + ": Better late than never! You will be next!" );
        }
      }

  if( message.contains("over.") )
      {
    memberDone(channel, m);
    if( m.equals(activeMember) ) nextMember(channel);
      }

  log( channel, "Scrum Members: " + scrumMembers );
  log( channel, "Active member: " + activeMember );
  log( channel, "State: " + state + ", since: " + previousStateChange );
  log( channel, "Previous members: " + previousMembers );
    }

    private void changeState(String channel, State state)
    {
  this.state = state;
  this.previousStateChange = Calendar.getInstance();
    }

    private State getState(String channel)
    {
  return this.state;
    }

    private void startScrum(String channel)
    {
  sendAction( channel, "starts daily scrum... Please everyone say 'hi'!" );
  changeState( channel, State.WAITING_ATTENDEES );
    }

    private boolean memberDone(String channel, Member m)
    {
  if( !previousMembers.contains(m) ) previousMembers.add(m);
 
  return scrumMembers.remove(m);
    }

    private void startReporting(String channel)
    {
        changeState( channel, State.WAITING_REPORTS );

      List<Member> list = new LinkedList( previousMembers );
  list.removeAll( scrumMembers );

  if( list.size() > 0 )
  {
    String members = null;
    for(Member m: list)
    {
      if( members == null ) members = m.getName();
      else members = members + ", " + m.getName();
    }

    sendMessage( channel, "Following participants not attending: " + members );
  }

  // this is the only place we can make a copy of the list of current scrum members
  // to be used in the next round when deciding previous members.
  this.previousMembers = new LinkedList( this.scrumMembers );

  nextMember( channel );
    }

    private void nextMember(String channel)
    {
  //changeState( channel, State.WAITING_REPORTS );

  Iterator<Member> i = scrumMembers.iterator();

  if( i.hasNext() )
      {
    Member m = i.next();

    // find the last on the list
    while( i.hasNext() ) m = i.next();

    sendMessage( channel, m.getName() + " please go ahead... (Just say 'over.' when you're done)" );
    this.activeMember = m;
      }
  else
      {
    endScrum(channel);
      }
    }

    private void endScrum(String channel)
    {
  this.activeMember = null;
  sendAction( channel, "ends daily scrum... Thank you all!" );
  changeState( channel, State.IDLE );
    }

    private void checkStatus(String channel)
    {
  State state = this.state;
  Calendar now = Calendar.getInstance();

  switch( state )
      {
      case IDLE:
    int dow = now.get( Calendar.DAY_OF_WEEK );

    if( now.get( Calendar.HOUR_OF_DAY ) == 11 && now.get( Calendar.MINUTE ) == 0 && now.get( Calendar.SECOND ) == 0 &&
        dow != Calendar.SATURDAY && dow != Calendar.SUNDAY )
        startScrum( channel );
    break;

      case WAITING_ATTENDEES:
    {
        // wait for 30 seconds of total silence
        Calendar then = (Calendar)now.clone();
        then.add( Calendar.SECOND, -30 );
        if( then.after( previousStateChange ) ) startReporting(channel);

        // wait for 10 seconds of silence after previous "hi"
        then = (Calendar)now.clone();
        then.add( Calendar.SECOND, -10 );
        if( then.after( previousStateChange ) )
        {
      boolean all_active = true;
      for(Member m2: previousMembers)
          {
        if( !scrumMembers.contains(m2) ) all_active = false;
          }
     
      // if all have activated themselves then lets get to work!
      if( all_active )
          {
        startReporting(channel);
          }
        }
    }
    break;

    // wait for 30 seconds
      case WAITING_REPORTS:
    now.add( Calendar.SECOND, -120 );
    if( now.after( previousStateChange ) )
        {
      memberDone(channel, activeMember);
      nextMember(channel);
        }
    break;
   
      default:
    quitServer( "Unknown state: " + state );
    break;
      }
    }

    private Member getMember(String channel, String nick, String login, String hostname)
    {
  if( members == null ) members = new HashMap();

  if( members.containsKey( nick ) )
      {
    return members.get( nick );
      }
  else
      {
    Member m = new Member(nick);
    members.put(nick, m);
    return m;
      }
    }

    private void log(String channel, String message)
    {
  System.out.println( channel + ": " + message );
    }


    /* ------------------------------------ */
   
    public void run()
    {
  try {
      while( true )
    {
        if( channel != null ) checkStatus(channel);
       
        Thread.currentThread().sleep(800);
    }
  } catch(java.lang.InterruptedException e) {
  }
    }
}
TOP

Related Classes of net.sourceforge.scrumbot.ScrumBot

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.