#!/usr/bin/perl

use POSIX;
$|=1;

# worth.pl -- find out the value of your stock, and figure out how much
#             longer you have to wait until you're fully vested.
#
#             By Jamie Zawinski <jwz@netscape.com> 20-Sep-96.
#             (Still workin' for da man.)
#
#             DzM (dzm@dzm.com) March 1, 2000
#             Found a stock URL that works. Yay.
#
#             Rob Crittenden <rcrit@netscape.com> 15-Sep-00.
#             Fixed vesting schedule quarterly problem 01-Jun-01.
#
#             DzM June 12, 2001
#             Added Total Unsold Vested and Total Unvested Worth
#             Reformatted report into cleaner columns
#             Added inspiring text to follow report.
#             Cleaned up some of the docs/comments
#
#             DzM June 18, 2001
#             Added HTTP header and HTML formatting to allow
#             script to be used as a home page
#
#             DzM July 1, 2001
#             Stock URL retired. Found new functional URL
#
#             DzM July 3, 2001
#             Added "change from last close" line
#             Fixed broken averaging in summaries
#
#             DzM July 30, 2001
#             Fixed calculation problem that caused options
#             to continue vesting after being fully vested
#
#             DzM October 17, 2001
#             Added logic that describes how much the Ticker
#             needs to raise to give the soul value again.
#             Also cleaned up some of the style.
#             Added color to the Change value in the report
#             Provided percentage of options vested (total)
#
#             DzM October 30, 2001
#             Fixed a problem with the RegExp that caused stock
#             changes of whole numbers (1, 2, etc) to be combined
#             with Percentage Change (2.5, 3.0 etc). This led to
#             misleading numbers where a change of $1, or 3.2% was
#             represented as $13.2.
#
#             DzM August 26, 2002
#             Small change to accomodate format change of NASDAQ web
#             site.
#
#             DzM November 30, 2002
#             Fixed format error that would cause only first five digits
#             to be displayed if, but some lucky happenstance, your
#             are not only not underwater but are also worth Real Actual Money.
#
#             Kousik Tue Apr 15 13:20:15 IST 2003 
#             Cosmetic changes; instead of CGI made a standalone script
#
#             Kousik Wed Aug 06 19:30:25 IST 2003 
#             Converted the $$$ to INR to get a real feeling (or pinch)
#             of the money
#
#             A.Kamesh January 13 2004
#             Added functionality to accept a walkaway date along with
#             the price. Now accepts price_at_a_date and calculates
#             networth of the portfolio on that date
#             Put in little validations
#             Added the post-tax INR figure to provide a sombering effect
#             Display amounts in crores :)
#
#             Kousik Mon Jun 28 19:55:21 IST 2004 
#             1. we go to currency converter only once
#             2. now we compute how much to invest to exercise,
#             3. and what'd be the return after 1 yr for LT tax
#             4. Also Rs is printed with more familiar commas

# limitations:
#  - only handles stock from one company
#  - the rounding has a lot to be desired

# enhancements (rcrit/DzM):
#  added support for multiple stock grants
#  added support for yearly vesting
#  added summary reporting page
#  added stock change display
#  added CGI capabilities
#  added much fluffy verbage to underwater options

####
#### Stocks array.
####
#### The format is:
#### ( index, "strike price : shares : sold shares : vest start : vest end : schedule" )
####
#### For schedule, m = monthly spread evenly along the vesting schedule
####               a = annual vesting - split equal percentage vested accross
####                   vesting lifespan (i.e. 4 year vesting schedule, 1/4 per year)
####

#### The format is:
#### ( index, "strike price : shares : sold shares : vest start : vest end : schedule" )
####
#### the first line should be "%stocks=(" and the last line ");" don't change them
#### for example:
# 
# %stocks=(       
# 
#         1, "48.50:1000:0:1-12-2001:01-12-2006:m",
#         2, "40.75:500:0:20-2-2002:20-2-2007:m",
#         ^     ^    ^  ^    ^         ^      ^
#         |     |    |  |    |         |      +-- monthly
#         |     |    |  |    |         +--------- vesting ends
#         |     |    |  |    +------------------- vesting starts
#         |     |    |  +------------------------ sold shares
#         |     |    +--------------------------- how many you have
#         |     +-------------------------------- grant price
#         +-------------------------------------- index #, keep incrementing
# 
# );

my $home = $ENV{HOME};
do "$home/.stockgrant" || 
    print `cat /users/kousik/.stockgrant_example` &&
    die "Don't you have a .stockgrant file in $home?\n";

#### What company was it that you worked for again?
$ticker = "CSCO";


#### You shouldn't need to change anything else.

############################################################################
############################################################################

#
# Print our CGI header and basic HTML formatting
#

#print "Content-type: text/html\n\n";
#print "<html>\n<head>\n<title>\nSoldier Stat\n</title>\n</head>\n<body>\n";

#
# URL to acquire current price at
#

$quote_url ="http://quotes.nasdaq.com/Quote.dll?" .
            "page=multi&mode=Stock&symbol=" . $ticker;

#   option 1
# $currency_converter ="http://in.finance.yahoo.com/m5?a=1&s=USD&t=INR&c=0";
#   option 2, more accurate
$currency_converter = "http://finance.yahoo.com/currency/convert?amt=1&from=USD&to=INR&submit=Convert";

#
# Acquire HTML to get the current value of $ticker
#

use Socket;
sub http_grab {

  # mostly snarfed from wwwgrab.pl

  local ($_) = @_;

  /^http:\/\/([^\/]*)\/*([^ ]*)/;
  my $site = $1;
  my $file = "/".$2;

  if (!$site) {
    die "$0: non-HTTP URL: " . $_ . "\n";
  }

  $_ = $site;
  /^([^:]*):*([^ ]*)/;
  $site = $1;
  my $port = $2;
  $port = 80 unless $port;

  my $hostname = $site;

  # Open a socket and get the data
  my ($sockaddr,$there,$response,$tries) = ("Snc4x8");
  my $there = pack($sockaddr,2,$port, &getaddress($hostname));
#  my ($a, $b, $c, $d) = unpack('C4', $hostaddr);

  my $proto = (getprotobyname ('tcp'))[2];

  if (!socket(S,AF_INET,SOCK_STREAM,$proto)) {
    die "$0:  Fatal Error.  $!\n"; }
  if (!connect(S,$there)) { die "$0:  Fatal Error.  $!\n"; }
  select(S);$|=1;
  select(STDOUT);$|=1;
  print S "GET $file HTTP/1.0\r\n";
  print S "\r\n";
  while(<S>) {
    s/&nbsp\;/ /;
    if (m@Last|\$ [0-9]|>[0-9]\.|Change@) {  # Oh No! Pipe buffer fills up!
      print $_;
    }
    if (m@USDINR@) { # S**t what a bad hack man - I spent 30 mins to figure
        # option 2, more accurate
        s/.*Exchange\<br\>Rate//g;
        print $_;    # this business out
    }
  }
  close(S);

  sub getaddress {
    my($host) = @_;
    my(@ary);
    @ary = gethostbyname($host);
    return(unpack("C4",$ary[4]));
  }
}

#
# Get the URL, strip the price from the returned HTML
# This whole thing is RegExp voo-doo. Avoid it.
#

sub parse_url {
  my ($url) = @_;

  pipe(PIPEIN, PIPEOUT) || die "Can't make pipe stdout";

  open(SAVEOUT, ">&STDOUT");
  open(STDOUT, ">&PIPEOUT") || die "Can't redirect stdout";
  select(STDOUT); $| = 1;       # make unbuffered

  http_grab $url;

  close(STDOUT);
  open(STDOUT, ">&SAVEOUT");
  close(PIPEOUT);

  while (<PIPEIN>) {
    if ( m@Last Sale@ ) {
      # read the next line
      $_ = <PIPEIN>;
      ( $per_share_value ) = m/\$ (\d+\.*\d*)</;
    }
    if ( m@Net Change@ ) {
      # read the next line
      $_ = <PIPEIN>;
      $down = m/class=\"red\"/;

      s/<!?[a-zA-Z0-9 \+\?\.\"=_:\/]+>//g;
      s/&nbsp\;/ /g;
      s/[0-9\.]+%//g;
      s/\t* *//g;

      $change = $_;
      $change = $change * -1 if ($down);
    }
  }
  if ($per_share_value == 0 || $per_share_value eq "" ) {
    die("Unable to find per-share price $per_share_value.\n");
  }
  close(PIPEIN);
}

sub parse_currency {
  my ($url) = @_;

  pipe(PIPEIN, PIPEOUT) || die "Can't make pipe stdout";

  open(SAVEOUT, ">&STDOUT");
  open(STDOUT, ">&PIPEOUT") || die "Can't redirect stdout";
  select(STDOUT); $| = 1;       # make unbuffered

  http_grab $url;

  close(STDOUT);
  open(STDOUT, ">&SAVEOUT");
  close(PIPEOUT);

  while (<PIPEIN>) {
#        option 1
#        if ( m@nowrap@ ) {
#       option 2, more accurate
        if ( m@yfnc_tabledata1@ ) {
           s/.*nowrap//g;
           s/.*<b>//g;
           s/<\/b>.*//g;
           $in_rupees = $_;
           chomp $in_rupees;
        }
  }
  close(PIPEIN);
}
#
# Beautify numbers (i.e. make 1000 be 1,000)
#

sub commify {
    my $rupee_or_dollar = shift;
    local ($_) = shift;

    $_ = int($_);

    if ($rupee_or_dollar) {
        s/^(-?\d+)(\d{2})(\d{3})/$1,$2,$3/;
        1 while s/^(-?\d+)(\d{2})/$1,$2/;
    } else {
        1 while s/^(-?\d+)(\d{3})/$1,$2/;
    }
    return $_;
}

#
# Turn your puny readable dates into lovely mktime dates
#

sub parse_date {
  local ($_) = shift;
  
  local ($month, $day, $year) = split(/\-/);
  #local ($day, $month, $year) = split(/\-/);
  $month = $month - 1;
  $year = $year - 1900;
  #             sec, min, hour,   mday,    mon,   year,  wday, yday,  isdst
  return mktime(  0,   0,    0,   $day, $month,  $year,     0,    0,     0);
}

#
# Main
#

$today = time();
#A.Kamesh Added Usage messages
$Fmt1="stockWorth.pl\n";
$Fmt2="stockWorth.pl stock-value (as of today assumed)\n";
$Fmt3="stockWorth.pl stock-value mm-dd-yyyy\n";
$Example1="stockWorth.pl (Your worth NOW, The Reality)\n"; 
$Example2="stockWorth.pl 30(Your worth assuming CSCO is \$30)\n"; 
$Example3="stockWorth.pl 40 01-31-2006 (CSCO is \$40 on 31st Jan 06)\n"; 
$Example="\n $Example1 $Example2 $Example3\n";
$Usage = "Usage:\n $Fmt1 $Fmt2 $Fmt3 \nExample:$Example";
$RUPEE = 1;
$DOLLAR = 0;

#Check no. of args
if ($#ARGV > 1) {
    die "$Usage";
}

if ($#ARGV==1) {
  #itsy-bitsy validations
  if ($ARGV[0] =~ /.+[-,a-z,A-Z].+/) {
      die "$Usage";
  }
  $per_share_value = $ARGV[0];
  $change = 0;
  #A.Kamesh Added walkout date acceptance functionality
  $today = &parse_date($ARGV[1]);
  print "Welcome to the \"Dream\" application\n\n";
} else { 
  if ($#ARGV==0) {
    if ($ARGV[0] =~ /.+[-,a-z, A-Z].+/) {
      die "$Usage";
    }
    $per_share_value = $ARGV[0];
    $change = 0;
  } else {
    parse_url $quote_url;
  }
}

if ($#ARGV == 1) {
    printf("Anticipated value of \"" . $ticker . "\" on $ARGV[1] is \$%.2f",
        $per_share_value);
} else {
    printf ( "\nToday's \"" . $ticker . "\" price is \$%.2f ", $per_share_value );
}

# if ( $change < 0 ) { # Make the number red if we're in negative range
#   printf ( "#990000" );
# }
# elsif ( $change > 0 ) { # Make the number green if we're in positive range
#   printf ( "#009900" );
# } 
# else { # Make the number black if it's sitting at zero
#   printf ( "#000000" );
# }

printf ( " (%+.2f)\n\n", $change );
#print "<pre>\n";

#
# Print the report header
#

print " Strike\t Total\t      %\t   Total  Unsold      Unsold   Unvested      Total\n";
print "  Price\tShares\t Vested\t  Vested  Vested\t   \$\t     \$   Unsold \$\n";
print " ~~~~~~ ~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~  ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ \n";

#
# Prep the report numbers
#

$sum_totalshares = 0;
$sum_totalworth = 0;
$sum_unsoldworth = 0;
$sum_unsoldvested = 0;
$sum_unvestedworth = 0;
$sum_totalvested = 0;
$min_underwater = 0;
$sum_to_invest = 0;
$sum_returned_long_term = 0;

#
# Perform the heavy lifting and figure out how much our options suck
#

foreach $strike (keys %stocks) {
  #### ( "strike price : shares : sold shares : vest start : vest end : vest_schedule" )
  ($strike_price, $total_shares, $shares_sold, $vest_s, $vest_e, $schedule) = split(/:/, $stocks{$strike});

  $vest_start = &parse_date($vest_s);
  $vest_end = &parse_date($vest_e);

#
# Determine the type of vesting (monthly/annual) and perform magic
#

  if ($schedule eq "m") {
    $portion_done = int ($today - $vest_start) / ($vest_end - $vest_start);
  } else {
    $portion_done= 0 ;
    $diff = int ($today - $vest_start);
    $diff = ($diff / 3600 ) / 24;
    $remainder = $diff;
    #printf(" ~> diff %d", $diff);
    while ($remainder > 365) {
      $portion_done++;
      $remainder -= 365;
    }
    $multiplier = $vest_end - $vest_start;
    $multiplier = int (($multiplier / 3600 ) / 24 / 365);
    $portion_done *= 1/$multiplier;
  }

  if ($today >= $vest_end) { # This keeps things from vesting after they hit 100%
    $shares_vested   = $total_shares;
    $shares_unvested = 0;
    $portion_done    = 1;
  } else {
    $shares_vested   = $total_shares * $portion_done;
    $shares_unvested = $total_shares - $shares_vested;
  }

  $shares_vested_and_unsold = $shares_vested - $shares_sold;

  $shares_vested = int($shares_vested);
  $shares_unvested = int($shares_unvested);
  $shares_vested_and_unsold = int($shares_vested_and_unsold);

  $sum_totalshares += $total_shares;
  $sum_unsoldvested += $shares_vested_and_unsold;

  $sum_totalvested += $shares_vested;

  $trade_value = ($per_share_value - $strike_price);

  if ( $trade_value > 0) {
    $sum_totalworth += ( $total_shares - $shares_sold ) * $trade_value;
    $sum_unsoldworth += $shares_vested_and_unsold * $trade_value;
    $sum_unvestedworth += ( $total_shares - $shares_vested ) * $trade_value;
    $sum_old_unvestedworth += ( $total_shares - $shares_vested ) * ( $trade_value + $change );
  } elsif (( $portion_done < 1 ) &&
	   (( $min_underwater == 0 ) || ( $min_underwater < $trade_value ))) {
    $min_underwater = $trade_value;
    $min_tanked_strike = $strike_price;
  }

#kousik:
$strike_temp = $strike_price;
if ( $per_share_value < $strike_price ) {
    $strike_price = $per_share_value;
} else {
   $sum_to_invest += $shares_vested_and_unsold * $strike_price;
   $sum_returned_long_term += $shares_vested_and_unsold * $per_share_value;
}

#
# Print the numbers for a single grant
#

  printf("\$%6.2f %6.6s   %5d%%   %6.6s  %6.6s  \$%9.9s \$%9.9s \$%9.9s\n",
	 $strike_temp,
	 commify ($DOLLAR, $total_shares),
	 ($portion_done * 100),
	 commify ($DOLLAR, $shares_vested),
	 commify ($DOLLAR, $shares_vested_and_unsold),
	 commify ($DOLLAR, $shares_vested_and_unsold * ($per_share_value - $strike_price)),
	 commify ($DOLLAR, ($total_shares - $shares_vested) * ($per_share_value - $strike_price)),
	 commify ($DOLLAR, ($total_shares - $shares_sold) * ($per_share_value - $strike_price))
	);
  }

print " ~~~~~~ ~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~  ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ \n";

#
# Print the summary
#

printf("        %6.6s   %5.1f%%   %6.6s  %6.6s  \$%9.9s \$%9.9s \$%9.9s\n",
       commify ($DOLLAR, $sum_totalshares),
       ( 100 * ($sum_totalvested / $sum_totalshares)),
       commify ($DOLLAR, $sum_totalvested),
       commify ($DOLLAR, $sum_unsoldvested),
       commify ($DOLLAR, $sum_unsoldworth),
       commify ($DOLLAR, $sum_unvestedworth),
       commify ($DOLLAR, $sum_totalworth)
      );

print " ~~~~~~ ~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~  ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ \n";
print "\n\n";

#
# Determine the current worth of unvested grants. Print inspiring message if any
# of the grants are not under water - if they're all under water print an inspiring
# message
#

if ($sum_unsoldworth <= 0) {
  printf("Your options are all worthless. Your soul has no value.\n");
  printf($ticker . "'s price needs to go up at least ");
  printf("\$%.2f (\$%.2f) to give your soul value.\n", 
	 (( -1 * $min_underwater ) + .01 ), ( $min_tanked_strike + .01 ));
  printf("Why are you still here little pawn?\n");
  }
else
  {
    printf("No homocidal spree today little pawn. Be happy. Your soul is worth \$%.9s.\n",
	   commify($DOLLAR, $sum_totalworth));
    printf("That's ");

    $sum_unvestedchange = ($sum_old_unvestedworth - $sum_unvestedworth);

    if ($sum_unvestedchange < 0) {
      printf("down \$%.6s",
	     commify($DOLLAR,  0 - $sum_unvestedchange ));
    }
    elsif ( $sum_unvestedchange == 0 ) {
	printf("no change");
      }
    else
      {
	printf("up \$%.6s",
	       commify( $DOLLAR, $sum_unvestedchange ));
      }

    printf(" from the last close.\n\nIf you walkout ");
    if ($#ARGV == 1) {
        printf("on $ARGV[1]");
    } else {
        printf("today");
    }
    printf(", you'd take \$%.9s. ", commify($DOLLAR, $sum_unsoldworth));
    parse_currency $currency_converter ;
#    printf("\n %.11s", $in_rupees);
    printf("\nThat's Rs %.11s in today's USD/INR exchange [%.5s].\n", 
    commify ($RUPEE, $sum_unsoldworth * $in_rupees) , $in_rupees);
    $ITAX=0.67;
    $post_tax =  $ITAX*$sum_unsoldworth;
    printf("Post-tax (33%) you get Rs %.11s in hand.\n\n", 
    commify ($RUPEE, $post_tax * $in_rupees));

    $rs_invested = $in_rupees * $sum_to_invest;
    $rs_returned = $in_rupees * (($sum_unsoldworth * 0.9) + 
                  ($sum_returned_long_term - $sum_unsoldworth));
    printf("If Rs %.15s invested today, you can exercise" . 
           " vested above water options.\n", 
           commify($RUPEE, $rs_invested));
    printf("One year later, if stock price stays at \$%.6s, you'll get" .
           " Rs %.15s in hand.\n", 
           $per_share_value, commify($RUPEE, $rs_returned));
    printf("That's Rs %.15s [%.5s%%]! Rs %.11s higher if you paid short term tax!\n\n", 
           commify($RUPEE, $rs_returned - $rs_invested),
           100 * ($rs_returned - $rs_invested) / $rs_invested,
           commify($RUPEE, ($rs_returned - $rs_invested) - ($post_tax * $in_rupees)));
  }


exit 0;
