 : split-trailing ( string -- string string/f )
     ":" split1 ;
 
+: copy-contents ( origin dest -- )
+    { [ >r parameters>> r> [ (>>command-parameters) ] [ (>>parameters) ] 2bi ]
+      [ >r line>>       r> (>>line) ]
+      [ >r prefix>>     r> (>>prefix) ]
+      [ >r command>>    r> (>>command) ]
+      [ >r trailing>>   r> (>>trailing) ]
+      [ >r timestamp>>  r> (>>timestamp) ]
+    } 2cleave ;
+
 PRIVATE>
 
 UNION: sender-in-prefix privmsg join part quit kick mode nick ;


<PRIVATE

GENERIC: irc-command-string ( irc-message -- string )

M: irc-message irc-command-string ( irc-message -- string ) command>> ;
M: ping        irc-command-string ( ping -- string )    drop "PING" ;
M: join        irc-command-string ( join -- string )    drop "JOIN" ;
M: part        irc-command-string ( part -- string )    drop "PART" ;
M: quit        irc-command-string ( quit -- string )    drop "QUIT" ;
M: nick        irc-command-string ( nick -- string )    drop "NICK" ;
M: privmsg     irc-command-string ( privmsg -- string ) drop "PRIVMSG" ;
M: notice      irc-command-string ( notice -- string )  drop "NOTICE" ;
M: mode        irc-command-string ( mode -- string )    drop "MODE" ;
M: kick        irc-command-string ( kick -- string )    drop "KICK" ;

GENERIC: irc-command-parameters ( irc-message -- seq )

M: irc-message irc-command-parameters ( irc-message -- seq ) parameters>> ;
M: ping        irc-command-parameters ( ping -- seq )    drop { } ;
M: join        irc-command-parameters ( join -- seq )    drop { } ;
M: part        irc-command-parameters ( part -- seq )    channel>> 1array ;
M: quit        irc-command-parameters ( quit -- seq )    drop { } ;
M: nick        irc-command-parameters ( nick -- seq )    drop { } ;
M: privmsg     irc-command-parameters ( privmsg -- seq ) name>> 1array ;
M: notice      irc-command-parameters ( norice -- seq )  type>> 1array ;
M: kick irc-command-parameters ( kick -- seq )
    [ channel>> ] [ who>> ] bi 2array ;
M: mode irc-command-parameters ( mode -- seq )
    [ name>> ] [ channel>> ] [ mode>> ] tri 3array ;

PRIVATE>

GENERIC: irc-message>client-line ( irc-message -- string )

M: irc-message irc-message>client-line ( irc-message -- string )
    [ irc-command-string ]
    [ irc-command-parameters " " sjoin ]
    [ trailing>> [ CHAR: : prefix ] [ "" ] if* ]
    tri 3array " " sjoin ;


: parse-irc-line ( string -- message )
    string>irc-message
    dup command>> {
        { "PING" [ ping new ] }
        { "NOTICE" [ notice new ] }
        { "001" [ logged-in new ] }
        { "433" [ nick-in-use new ] }
        { "353" [ names-reply new ] }
        { "JOIN" [ join new ] }
        { "PART" [ part new ] }
        { "NICK" [ nick new ] }
        { "PRIVMSG" [ privmsg new ] }
        { "QUIT" [ quit new ] }
        { "MODE" [ mode new ] }
        { "KICK" [ kick new ] }
        [ drop unhandled new ]
    } case
    [ copy-contents ] keep ;
