﻿//
// TSS decoder / HTML encoder
// Tantek Çelik http://tantek.com/ 2010-150
// decodes:
// {(p:v;)+}?       // whole tweet rule
// (*{(p:v;)+})?    // generic rule for all runs
// (n,n{(p:v;)+})*  // relative offset, length run specific rule
//
// requires cassis.js (http://cassisproject.com) http://tantek.com/cassis.js
//


$decomparray = 
{
bd:     ["background"],
bdat:   ["background-attachment"],
bdcr:   ["background-color"],
bdie:   ["background-image"],
bdpn:   ["background-position"],
bdpnxx: ["background-position-x"],
bdpnyy: ["background-position-y"],
bdrt:   ["background-repeat"],
br:     ["border"],
brbm:   ["border-bottom"],
brbmcr: ["border-bottom-color"],
brbmse: ["border-bottom-style"],
brbmwh: ["border-bottom-width"],
brce:   ["border-collapse"],
brcr:   ["border-color"],
brlt:   ["border-left"],
brltcr: ["border-left-color"],
brltse: ["border-left-style"],
brltwh: ["border-left-width"],
brrt:   ["border-right"],
brrtcr: ["border-right-color"],
brrtse: ["border-right-style"],
brrtwh: ["border-right-width"],
brsg:   ["border-spacing"],
brse:   ["border-style"],
brtp:   ["border-top"],
brtpcr: ["border-top-color"],
brtpse: ["border-top-style"],
brtpwh: ["border-top-width"],
brwh:   ["border-width"],
bm:     ["bottom"],
cnse:   ["caption-side"],
cr:     ["color"],
cp:     ["clip"],
ct:     ["content"],
crit:   ["counter-increment"],
crrt:   ["counter-reset"],
ce:     ["cue"],
cear:   ["cue-after"],
cebe:   ["cue-before"],
dn:     ["direction"],
dy:     ["display"],
en:     ["elevation"],
eycs:   ["empty-cells"],
fr:     ["filter"],
ft:     ["float"],
ftfy:   ["font-family"],
ftse:   ["font-size"],
ftseat: ["font-size-adjust"],
ftsh:   ["font-stretch"],
ftvt:   ["font-variant"],
ftwt:   ["font-weight"],
ht:     ["height"],
ieme:   ["ime-mode"],
iese:   ["include-source"],
lrbdcr: ["layer-background-color"],
lrbdie: ["layer-background-image"],
ltfw:   ["layout-flow"],
ltgd:   ["layout-grid"],
ltgdcr: ["layout-grid-char"],
ltgdcrsg:       ["layout-grid-char-spacing"],
ltgdle: ["layout-grid-line"],
ltgdme: ["layout-grid-mode"],
ltgdte: ["layout-grid-type"],
lt:     ["left"],
lrsg:   ["letter-spacing"],
lebk:   ["line-break"],
leht:   ["line-height"],
ltse:   ["list-style"],
ltseie: ["list-style-image"],
ltsepn: ["list-style-position"],
ltsete: ["list-style-type"],
mn:     ["margin"],
mnbm:   ["margin-bottom"],
mnlt:   ["margin-left"],
mnrt:   ["margin-right"],
mntp:   ["margin-top"],
mrot:   ["marker-offset"],
 ms:    ["marks"],
mxht:   ["max-height"],
mxwh:   ["max-width"],
mnht:   ["min-height"],
mnwh:   ["min-width"],
'-mzbg':        ["-moz-binding"],
'-mzbrrs':      ["-moz-border-radius"],
'-mzbrtpcs':    ["-moz-border-top-colors"],
'-mzbrrtcs':    ["-moz-border-right-colors"],
'-mzbrbmcs':    ["-moz-border-bottom-colors"],
'-mzbrltcs':    ["-moz-border-left-colors"],
'-mzoy':        ["-moz-opacity"],
'-mzoe':        ["-moz-outline"],
'-mzoecr':      ["-moz-outline-color"],
'-mzoese':      ["-moz-outline-style"],
'-mzoewh':      ["-moz-outline-width"],
'-mztm':      ["-moz-transform"],
'-mzurfs':      ["-moz-user-focus"],
'-mzurit':      ["-moz-user-input"],
'-mzurmy':      ["-moz-user-modify"],
'-mzurst':      ["-moz-user-select"],
os:     ["orphans"],
oe:     ["outline"],
oecr:   ["outline-color"],
oese:   ["outline-style"],
oewh:   ["outline-width"],
ow:     ["overflow"],
owXX:   ["overflow-X"],
owYY:   ["overflow-Y"],
pg:     ["padding"],
pgbm:   ["padding-bottom"],
pglt:   ["padding-left"],
pgrt:   ["padding-right"],
 pgtp:  ["padding-top"],
pebkar: ["page-break-after"],
pebkbe: ["page-break-before"],
pebkie: ["page-break-inside"],
pear:   ["pause-after"],
pebe:   ["pause-before"],
ph:     ["pitch"],
phre:   ["pitch-range"],
pydg:   ["play-during"],
pn:     ["position"],
 qs:    ["quotes"],
'-re':  ["-replace"],
rs:     ["richness"],
rt:     ["right"],
ryan:   ["ruby-align"],
ryog:   ["ruby-overhang"],
rypn:   ["ruby-position"],
'-stlkse':      ["-set-link-source"],
se:     ["size"],
sk:     ["speak"],
skhr:   ["speak-header"],
sknl:   ["speak-numeral"],
skpn:   ["speak-punctuation"],
shre:   ["speech-rate"],
ss:     ["stress"],
srawcr: ["scrollbar-arrow-color"],
srbecr: ["scrollbar-base-color"],
srdkswcr:       ["scrollbar-dark-shadow-color"],
srfecr: ["scrollbar-face-color"],
srhtcr: ["scrollbar-highlight-color"],
srswcr: ["scrollbar-shadow-color"],
sr3dltcr:       ["scrollbar-3d-light-color"],
srtkcr: ["scrollbar-track-color"],
telt:   ["table-layout"],
ttan:   ["text-align"],
ttanlt: ["text-align-last"],
ttdn:   ["text-decoration"],
ttit:   ["text-indent"],
ttjy:   ["text-justify"],
 ttow:  ["text-overflow"],
ttsw:   ["text-shadow"],
tttm:   ["text-transform"],
ttae:   ["text-autospace"],
ttkase: ["text-kashida-space"],
ttuepn: ["text-underline-position"],
tp:     ["top"],
uebi:   ["unicode-bidi"],
'-uelkse':      ["-use-link-source"],
vlan:   ["vertical-align"],
vy:     ["visibility"],
vefy:   ["voice-family"],
ve:     ["volume"],
wese:   ["white-space"],
ws:     ["widows"],
wh:     ["width"],
wdbk:   ["word-break"],
 wdsg:  ["word-spacing"],
wdwp:   ["word-wrap"],
wgme:   ["writing-mode"],
zzix:   ["z-index"],
zm:     ["zoom"]}
;



function decompcss($s) {
  if (!$s) return $s;
  $s = explode(';',$s);
  for ($i=count($s)-1;$i>=0;$i--) {
    $pv = explode(':',$s[$i]);
    if ($pv[0]) {
      $pp = $decomparray[$pv[0]];
      $s[$i] = strcat( $pp ? $pp : $pv[0], ':', $pv[1]);
    }
  }
  $s = implode(';',$s);
  return $s;
}

function styledtweet($t,$s) {
  $stret = "<div";
  
  $s = explode('}',$s); // no } in property names or values
  $ri = 0;

  // look for whole tweet style
  if (substr($s[0],0,1)=='{') {
    // apply it to the div for the tweet
    $stret = strcat($stret,' style="', decompcss(substr($s[0],1,strlen($s[0])-1)), '"');
    $ri++;
  }
  
  $stret = strcat($stret, ">");
  
  $grule = "";
  // look for generic rule for all runs
  if (substr($s[$ri],0,2)=='*{') {
    // save off the declarations without start/end {}
    $grule = decompcss(substr($s[$ri],2,strlen($s[$ri])-2));
    $ri++;   
  }
   
  $toff = 0;
  // look for rules for runs
  if ($s!="") {
    while ($ri<count($s)-1) {
     // for each one
     $arule = explode('{',$s[$ri]);
     $soff = explode(',',$arule[0]);
     $soff[0] -= 0;
     $soff[1] -= 0;
     
     // output characters to skip
     if ($soff[0] > 0) {
       $stret = strcat($stret, substr($t,$toff,$soff[0]));
     }
     $toff += $soff[0];
    
          
     // apply generic declaraton properties
     // apply specific properties
     // output a styled span for the rule
     $stret = strcat($stret, '<span style="', $grule, decompcss($arule[1]),'">', 
                     substr($t, $toff, $soff[1]), '</span>');
     $toff += $soff[1];   
     $ri++;
    }
  }
  
  if (strlen($t)-$toff > 0) {
    $stret = strcat($stret, substr($t, $toff, strlen($t)-$toff));
  }
  
  return strcat($stret,'</div>');
}
