\n";
        $body .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
        $body .= "\n\n";
    };
    # used for error messages
    my $err = sub {
        $title = "Error";
        $body = '';
        $authasform->() if $remote;
        $body .= "";
        return;        
    };
    # authenticate user
    $remote = LJ::get_remote();
    return $err->('You must be logged in to view your styles.') 
        unless $remote;
    my $authas = $GET{'authas'} || $remote->{'user'};
    my $u = LJ::get_authas_user($authas);
    return $err->('You could not be authenticated as the specified user.')
        unless $u;
    return $err->($remote->{user} eq $u->{user} ?
            'Your account type does not allow advanced customization.' :
            'The selected user\'s account type does not allow advanced customization.' )
        unless LJ::get_cap($u, 's2styles');
    # extra arguments for get requests
    my $getextra = $authas ne $remote->{'user'} ? "?authas=$authas" : '';
    my $getextra_amp = "&authas=$authas" if $getextra;
    # style id to edit, if we have one
    # if we have this we're assumed to be in 'edit' mode
    my $id = $GET{'id'}+0;
    my $dbh = LJ::get_db_writer();
    # variables declared here, but only filled in if $id
    my ($core, $layout);      # scalars
    my ($pub, $ulay, $style); # hashrefs
    # start of output
    $title = "Styles";
    $body = BML::ml("Backlink", {
        'link' => './',
        'text' => 'Advanced Customization',
    }) . "\n";
    $body .= BML::ml("Actionlink", {
        'link' => "Your Layers",
    }) . "\n";
    # edit mode
    if ($id) {
        # load style
        $style = LJ::S2::load_style($id);
        return $err->('Style not found') unless $style;
        # check that they own the style
        return $err->("You do not own this style.")
            unless $style->{'userid'} == $u->{'userid'};
        # use selected style
        if ($POST{'action:usestyle'}) {
            # save to db and update user object
            LJ::set_userprop($u, "stylesys", '2');
            LJ::set_userprop($u, "s2_style", $id);
            return BML::redirect("styles.bml$getextra");
        }
        # get public layers
        $pub = LJ::S2::get_public_layers();
        # get user layers
        $ulay = LJ::S2::get_layers_of_user($u);
        # find effective layerids being used
        my %eff_layer = ();
        my @other_layers = ();
        foreach (qw(i18nc layout theme i18n user)) {
            my $lid = $POST{$_} eq "_other" ? $POST{"other_$_"} : $POST{$_};
            next unless $lid;
            $eff_layer{$_} = $lid;
            unless ($ulay->{$eff_layer{$_}} || $pub->{$eff_layer{$_}}) {
                push @other_layers, $lid;
            }
        }
        # core lid (can't use user core layer)
        $POST{'core'} ||= $POST{'core_hidden'};
        $core = defined $POST{'core'} ? $POST{'core'} : $style->{'layer'}->{'core'};
        unless ($core) { # default to highest numbered core
            map { $core = $_ if $pub->{$_}->{'type'} eq 'core' && /^\d+$/ && 
                                $pub->{$_}->{'majorversion'} > $pub->{$core}->{'majorversion'} } keys %$pub;
            # update in POST to keep things in sync
            $POST{'core'} = $core;
        }
        # layout lid
        $layout = $POST{'action:change'} ? $eff_layer{'layout'} : $style->{'layer'}->{'layout'};
        # if we're changing core, clear everything
        if ($POST{'core'} && $style->{'layer'}->{'core'} &&
            $POST{'core'} != $style->{'layer'}->{'core'}) {
            foreach (qw(i18nc layout theme i18n user)) {
                delete $eff_layer{$_};
            }
            undef $layout;
        }
        # if we're changing layout, clear everything below
        if ($eff_layer{'layout'} && $style->{'layer'}->{'layout'} &&
            $eff_layer{'layout'} != $style->{'layer'}->{'layout'}) {
            foreach (qw(theme i18n user)) {
                delete $eff_layer{$_};
            }
        }
        # set up start of output
        $title = "Edit Style";
        $body .= "
" . BML::ml('Backlink', { 'text' => 'Your Styles', 'link' => "styles.bml$getextra" }) . "\n";
        ### process edit actions
        # delete
        if ($POST{'action:delete'}) {
            LJ::S2::delete_user_style($u, $id);
            undef $id; # don't show form below
            return BML::redirect("styles.bml$getextra");
        }
        # save changes
        if ($POST{'action:change'} || $POST{'action:savechanges'}) {
            # are they renaming their style?
            if ($POST{'stylename'} && $style->{'name'} &&
                $POST{'stylename'} ne $style->{'name'}) {
                # update db
                my $styleid = $style->{'styleid'};
                $dbh->do("UPDATE s2styles SET name=? WHERE styleid=? AND userid=?",
                         undef, $POST{'stylename'}, $styleid, $u->{'userid'});
                LJ::MemCache::delete([$styleid, "s2s:$styleid"]);
                # update style object
                $style->{'name'} = $POST{'stylename'};
            }
            # load layer info of any "other" layers
            my %other_info = ();
            if (@other_layers) {
                LJ::S2::load_layer_info(\%other_info, \@other_layers);
                foreach (@other_layers) {
                    return $err->("Layer not found: $_") unless exists $other_info{$_};
                    return $err->("Layer not public: $_") unless $other_info{$_}->{'is_public'};
                }
            }
            
            # error check layer modifications
            my $get_layername = sub {
                my $lid = shift;
                my $name;
                $name = $pub->{$lid}->{'name'} if $pub->{$lid};
                $name ||= $ulay->{$lid}->{'name'} if $ulay->{$lid};
                $name ||= "#$lid";
                return $name;
            };
            # check layer hierarchy
            my $error_check = sub {
                my ($type, $parentid) = @_;
                my $lid = $eff_layer{$type};
                next if ! $lid;
                my $layer = $ulay->{$lid} || $pub->{$lid} || LJ::S2::load_layer($lid);
                my $parentname = $get_layername->($parentid);
                my $layername = $get_layername->($lid);
                # is valid layer type?
                return "Invalid layer type: $layername is not a $type layer"
                    if $layer->{'type'} ne $type;
                # is a child?
                return "Layer hierarchy mismatch: $layername is not a child $type layer of $parentname"
                    unless $layer->{'b2lid'} == $parentid;
                return undef;
            };
            # check child layers of core
            foreach my $type (qw(i18nc layout)) {
                my $errmsg = $error_check->($type, $core);
                return $err->($errmsg) if $errmsg;
            }
            # don't check sub-layout layers if there's no layout
            if ($layout) {
                # check child layers of selected layout
                foreach my $type (qw(theme i18n user)) {
                    my $errmsg = $error_check->($type, $layout);
                    return $err->($errmsg) if $errmsg;
                }
            }
            # save in database
            my @layers = ( 'core' => $core );
            push @layers, map { $_, $eff_layer{$_} } qw(i18nc layout i18n theme user);
            LJ::S2::set_style_layers($u, $style->{'styleid'}, @layers);
            # redirect if they clicked the bottom button
            return BML::redirect("styles.bml$getextra") if $POST{'action:savechanges'};
        }
    # no style id, process actions for non-edit mode
    # and load in data necessary for style list
    } else {
        # load user styles
        my $ustyle = LJ::S2::load_user_styles($u);
        # process create action
        if ($POST{'action:create'} && $POST{'stylename'}) {
            return $err->('You have reached your maximum number of styles.')
                if scalar(keys %$ustyle) >= LJ::get_cap($u, 's2stylesmax');
            my $styleid = LJ::S2::create_style($u, $POST{'stylename'});
            return $err->('Style not created: Database error') unless $styleid;
            return BML::redirect("styles.bml?id=$styleid$getextra_amp");
        }
        # load style currently in use
        LJ::load_user_props($u, 's2_style');
        # set up page header
        $title = "Your Styles";
        $authasform->();
        $body .= "
\n";
        # show style listing
        $body .= "\n";
        if (%$ustyle) {
            my $journalbase = LJ::journal_base($u);
            foreach my $styleid (sort { $ustyle->{$a} cmp $ustyle->{$b} || $a <=> $b} keys %$ustyle) {
                $body .= " | ";
                $body .= LJ::html_submit('action:edit', 'Edit') . " ";
                $body .= LJ::html_submit('action:delete', 'Delete', 
                                         { 'onclick' => "return confirm('Are you sure you want to delete style \#$styleid?')" }) . " ";
                $body .= LJ::html_submit('action:usestyle', 'Use', { 'disabled' => $styleid == $u->{'s2_style'} }),
                $body .= " | 
\n";
            }
        } else {
            $body .= "| none | 
\n";
        }
        $body .= "
\n";
    }
    ### show create / edit form
    my $extra = $id ? "?id=$id" : '';
    $extra .= $extra ? $getextra_amp : $getextra;
    $body .= "\n", return unless $id;
    # from here on we have $pub, $ulay, and $style filled in
    # sub to take a layer type, core, and parent layout
    # and return a list of options to feed to LJ::html_select()
    my $layerselect = sub {
        my ($type, $b2lid) = @_;
        my @opts = ();
        # returns html_select to caller
        my $html_select = sub {
            my $dis = scalar(@opts) > 2 ? 0 : 1;
            my $lid = $POST{'action:change'} ? $POST{$type} : $style->{'layer'}->{$type};
            $lid = $POST{"other_$type"} if $lid eq "_other";
            my $sel = ($lid && ! $pub->{$lid} && ! $ulay->{$lid}) ? "_other" : $lid;
            return [ LJ::html_select({ 'name' => $type, 'id' => "select_$type",
                                       'onChange' => "showOther('$type')",
                                       'selected' => $sel,
                                       'disabled' => $dis }, @opts), { 'disabled' => $dis, } ];
        };
        # greps, and sorts a list
        my $greplist = sub {
            my $ref = shift;
            return  sort { $ref->{$a}->{'name'} cmp $ref->{$b}->{'name'} || $a <=> $b}
                    grep { $ref->{$_}->{'type'} eq $type && $ref->{$_}->{'b2lid'} == $b2lid && /^\d+$/}
                    keys %$ref;
        };
        
        # public layers
        my $name = $type eq 'core' ? 'majorversion' : 'name';
        push @opts, map { $_, $pub->{$_}->{$name} } $greplist->($pub);
        # no user core layers
        return $html_select->() if $type eq 'core';
        # user layers
        push @opts, ('', '---');
        my $startsize = scalar(@opts);
        push @opts, map { $_, "$ulay->{$_}->{'name'} (\#$_)" } $greplist->($ulay);
        # if we didn't push anything above, remove dividing line
        pop @opts, pop @opts unless scalar(@opts) > $startsize;
        # add option for other layerids
        push @opts, ('_other', 'Other ...');
        # add blank option to beginning of list
        unshift @opts, ('', @opts ? '' : ' ');
        return $html_select->();
    };
    my $layerother = sub {
        my $name = shift;
        my $olid = $POST{'action:change'} ? $POST{"other_$name"} : $style->{'layer'}->{$name};
        my $disp = 'none';
        my $val;
        if ($olid && ! $pub->{$olid} && ! $ulay->{$olid}) {
            $disp = 'inline';
            $val = $olid;
        }
        return "Layerid: " .
            LJ::html_text({ 'name' => "other_$name", 'id' => "other_$name",
                            'size' => 6, 'value' => $val }) .
            "
";
    };
    ### core version
    $body .= "\n";
    $body .= "\n";
    $body .= "| Core Version:  | ";
    my $coresel = $layerselect->('core', 0);
    $body .= $coresel->[0];
    $body .= LJ::html_hidden('core_hidden', $core);
    my $dis = $coresel->[1]->{'disabled'} ? { 'disabled' => 'disabled' } : undef;
    $body .= " " . LJ::html_submit('action:change', 'Change', $dis) . " | 
\n";
    $body .= "
\n";
    ### i18nc / layout
    $body .= "\n";
    # i18nc
    $body .= "| Language (i18nc):  | ";
    $body .= $layerselect->('i18nc', $core)->[0];
    $body .= $layerother->('i18nc');
    $body .= " | 
\n";
    # layout
    $body .= "| Layout:  | ";
    my $layoutsel = $layerselect->('layout', $core);
    $body .= $layoutsel->[0];
    $body .= $layerother->('layout');
    my $dis = $layoutsel->[1]->{'disabled'} ? { 'disabled' => 'disabled' } : undef;
    $body .= " " . LJ::html_submit("action:change", "Change", $dis) . "  | 
\n";
    $body .= "
\n";
    # do we need to show the rest of the form?
    $body .= "\n", return unless $layout;
    ### theme / i18n / user
    # theme
    $body .= "\n";
    $body .= "| Language (i18n):  | ";
    $body .= $layerselect->('i18n', $layout)->[0];
    $body .= $layerother->('i18n') . " | 
\n";
    $body .= "| Theme:  | ";
    $body .= $layerselect->('theme', $layout)->[0];
    $body .= $layerother->('theme') . " | 
\n";
    $body .= "| User:  | ";
    $body .= $layerselect->('user', $layout)->[0];
    $body .= $layerother->('user') . " | 
\n";
    $body .= "|   | ";
    $body .= LJ::html_submit('action:savechanges', 'Save Changes') . " | 
\n";
    $body .= "
\n";
    # end edit form
    $body .= "\n";
    return;
}
_code?>
head<=
<=head
body=>
bodyopts=>onLoad="pageload();"
page?>