<?php
require_once 'Smarty.class.php';
require_once 
'Cache/Lite.php';
require_once 
'HTTP/Request.php';

// username regex
$user_regex '/^[\w_]{1,15}$/D';
// userpic stuff
$url_open '<url>';
$url_close '</url>';
// userpic max size
$userpic_max_size 100;
$max_entry_len 65535;

// init Smarty
$smarty =& new Smarty();

// init Cache_Lite
$cache =& new Cache_Lite( array( 'cacheDir' => 'cache/',
                                 
//          sec*min*hour*day
                                
'lifeTime' => 60*60*24*2,
                                
'automaticSerialization' => true ) );
// NOTE: Cache stores fetched pages, so identifiers are URLs

// init HTTP_REQUEST
$lj =& new HTTP_Request();
$lj->addHeader'HTTP_USER_AGENT''CollageBot 0.1; http://toys.atrus.org/ljca/; atrus@atrus.org');
$lj->addHeader'X-PHP-Version'phpversion());
$lj->addHeader'REFERER''http://livejournal.com/bots/' );
$lj->addHeader'CONNECTION''keep-alive' );
$lj->addHeader'KEEP_ALIVE'300 );

// define a couple useful functions
function fatalError$message ) {
    global 
$smarty;
    
$smarty->assign'error'$message );
    
$smarty->display'error.tpl' );
    exit;
}

function 
getURL$url ) {
    global 
$lj;
    global 
$user_link;
    
$retry_count 3;
    
// in seconds
    
$retry_timeout 0.1;
    
    
$lj->setURL$url );
    
    
$failed true;
    for( 
$i 0; ( $i $retry_count ) && $failed$i++ ) {
        
$response $lj->sendRequest();
        
$failed PEAR::isError($response);
        if( 
$failed sleep$retry_timeout );
    }
    
    if( 
$i == $retry_count ) {
        
fatalError'Unable to get the friends list and/or icons for that user (' .
                    
$user_link') for some strange reason: ' .
                    
$response->getMessage() );
    }
    
    return 
$lj->getResponseBody();
}

function 
genUserLink$user ) {
    return 
'<a href="http://www.livejournal.com/userinfo.bml?user=' $user '">'.
        
'<img src="http://stat.livejournal.com/img/userinfo.gif" alt="[info]" width="17" height="17" style="vertical-align:bottom;border:0;" /></a>' .
        
'<a href="http://www.livejournal.com/users/' $user '/"><b>' .
        
$user '</b></a>';
}

// load form data
$make_links $_GET'link' ][0] == 'yes';
$in_out strtolower$_GET'in_out' ] );
$size strtolower$_GET'size' ] );
$opac strtolower$_GET'opac' ] );
$user get_magic_quotes_gpc()? stripslashes$_GET'user' ] ) : $_GET'user' ];
$user_link genUserLink$user );

$smarty->assign'user'$user );
$smarty->assign'in_out_arr', array( 'out''in''both' ) );
$smarty->assign'in_out'$in_out );
$smarty->assign'link_arr', array( 'yes' ) );
$smarty->assign'links'$make_links );
$smarty->assign'size_arr', array( 'small''medium''large' ) );
$smarty->assign'size'$size );
$smarty->assign'opac_arr', array( 'light''medium''heavy' ) );
$smarty->assign'opac'$opac );

if( !
array_key_exists'user'$_GET ) ) {
    
$smarty->display'form.tpl' );
    exit;
}

// fetch friends
// http://www.livejournal.com/misc/fdata.bml?user=
$friends = array();
$url 'http://www.livejournal.com/misc/fdata.bml?user=' $user;
if( !( 
$friends $cache->get$url ) ) ) {
        
    
$response getURL$url );
    
$response explode"\n"$response );
    
    
$friends = array();
    foreach( 
$response as $val ) {
        
$first substr$val0);
        if( 
$first == '#' ) {
            
// do nothing
        
} else if( $first == '!' ) {
            
$friends $val;
            break;
        } else if( 
$first == '>' ) {
            
$friends'out' ][] = substr$val);
        } else if( 
$first == '<' ) {
            
$friends'in' ][] = substr$val);
        }
    }
    
    
$cache->save$friends$url );
}

if( 
is_string$friends ) ) {
    if( 
preg_match$user_regex$user ) ) {
        
fatalError'The username you entered ('$user_link .
                    
') is incorrect or they have no friends listed' );
    } else {
        
fatalError'The username you entered ('$user .
                    
') does not follow LJ\'s rules' );
    }
}

// filter friends by edge type now
if( $in_out == 'both' ) {
    
$friends array_uniquearray_merge$friends'in' ],
                                          
$friends'out' ] ) );
} else if( 
$in_out == 'in' ) {
    
$friends $friends'in' ];
} else {
    
$friends $friends'out' ];
}

if( 
count$friends ) < ) {
    
fatalError'That user (' $user_link .
                
') has have no friends of the selected type listed' );
}

$friends_urls = array();
// fetch userpic URLs
foreach( $friends as $val ) {
    
$url 'http://www.livejournal.com/users/' .
        
$val '/data/rss';
    
$pic_url $cache->get$url );
    if( 
$pic_url === false ) {
        
$response getURL$url );
        
        
// pull userpic URL out of RSS feed
        
        // 425 is good place to start, skips most of the begining RSS junk
        
$start strpos$response$url_open425 );
        if( 
$start !== false ) {
            
$start += strlen$url_open );
            
// 40 is good place to start, skips most of URL
            
$end strpos(  $response$url_close$start+40 );
            if (!
$start) echo "miss\n";
            
$pic_url substr$response$start$end-$start);;
        } else {
            
$pic_url '';
        }
        
        
$cache->save$pic_url$url );
    }
    if( !empty( 
$pic_url ) ) {
        
$friends_urls[] = array( $val$pic_url );
    }
}

// randomize order
shuffle$friends_urls );

$num count$friends_urls );
$row_size ceilsqrt$num ) );
$area_size $userpic_max_size $row_size;
if( 
$size == 'small' ) {
    
$area_size = (int) rand$area_size/4$area_size/);
} else if( 
$size == 'large' ) {
    
$area_size = (int) rand$area_size*.75$area_size );
} else {
    
// default to medium
    
$area_size = (int) rand$area_size/2$area_size*.75 );
}
if( 
$opac == 'light' ) {
    
$opac_low 1;
    
$opac_high 6;
} else if( 
$opac == 'medium' ) {
    
$opac_low 3;
    
$opac_high 8;
} else {
    
// heavy is default
    
$opac_low 5;
    
$opac_high 10;
}
$max_pos $area_size $userpic_max_size;

$margin 10;

$collage '<div style="text-align: center;';
$collage .= 'width: ' . ( $area_size $margin*2  10 ) . 'px;';
$collage .= 'height: ' .( $area_size  $margin*80 ). 'px;';
$collage .= '">';
$collage .= '<span style="font-size: 2.5em;">~';
$collage .= $user;
$collage .= '~</span>';
$collage .= '<div style="';
$collage .= 'margin:' $margin 'px;';
$collage .= 'padding:0px;';
$collage .= 'border-width:4px;';
$collage .= 'border-style:ridge;';
$collage .= 'width:' $area_size 'px;';
$collage .= 'height:' $area_size 'px;';
$collage .= '">';

foreach( 
$friends_urls as $val ) {
    list( 
$friend_name$val ) =  $val;
    
    
$link 'http://www.livejournal.com/userinfo.bml?user=' $friend_name;
    
$top rand1$max_pos );
    
$left rand1$max_pos );
    
$opacity rand$opac_low$opac_high );
    
    
$style 'style="';
    
$style .= 'position: relative;';
    
$style .= 'top:' $top 'px;';
    
$style .= 'left:' $left 'px;';
    
// support IE
    
$style .= 'filter:alpha(opacity=' $opacity*10 ');';
    
// suport old Mozilla
    
$style .= '-moz-opacity:' $opacity/10 ';';
    
// support latest CSS spec
    
$style .= 'opacity:' $opacity/10 ';';
    
$style .= '"';
    
    
// trick the browser into anchoring everything in the upper left corner
    // (relative positioning = prev_element_size + cur_element_pos)
    // ( pos = 0 + pos ;)
    
$collage .= '<div style="width:0;height:0;">';
    if( 
$make_links ) {
        
$collage .= '<a href="' $link '"' .$style ' >';
        
$collage .= '<img src="' $val .'" style="border: 0px"/>';
        
$collage .= '</a>';
    } else {
        
$collage .= '<img src=' $val .' ' $style '/>';
    }
    
$collage .= '</div>';
}

$collage .= '</div>';
$collage .= '<span style="font-size: 0.7em;">';
$collage .= '<a href="http://toys.atrus.org/ljac/">LJAC</a> by ';
$collage .= genUserLink'atrustheotaku' );
$collage .= '. Original FriendsCollage by ';
$collage .= genUserLink'teemus' );
$collage .= '</span></div>';

$collage_len strlen$collage );
$remaining_len $max_entry_len $collage_len;

$smarty->assign'collage'$collage );
$smarty->assign'collage_len'$collage_len );
$smarty->assign'remaining_len'$remaining_len );

$smarty->display'collage.tpl' );

?>