fe742525b748e21a704e207382aa85fd83226844
[id3fs.git] / lib / ID3FS / Path / Node.pm
1 package ID3FS::Path::Node;
2
3 use strict;
4 use warnings;
5
6 sub new
7 {
8     my $proto=shift;
9     my $class=ref($proto) || $proto;
10     my $self={};
11     bless($self,$class);
12
13     $self->left(shift);
14     $self->op(shift);
15     $self->right(shift);
16
17     return $self;
18 }
19
20 sub set
21 {
22     my($self, $name, $val)=@_;
23     if(defined($val))
24     {
25         $self->{$name}=$val;
26     }
27     return $self->{$name};
28 }
29
30 sub left  { return shift->set("left",  shift); }
31 sub right { return shift->set("right", shift); }
32 sub op    { return shift->set("op",    shift); }
33
34 sub print
35 {
36     my($self)=@_;
37     my $op=$self->op();
38     my $left=$self->left();
39     my $right=$self->right();
40     return "" unless($left || $right);
41     my $str .= $self->print_node($left);
42     $str .= (" " . $op->{name} . " ") if($op);
43     $str .= $self->print_node($right);
44     if($op || ($left && $right))
45     {
46         $str="(" . $str . ")";
47     }
48     return $str;
49 }
50
51 sub print_node
52 {
53     my($self, $node)=@_;
54     return "" unless(defined($node));
55     return $node->print() if(ref($node) eq "ID3FS::Path::Node");
56     return $node->{name};
57 }
58
59 sub to_sql
60 {
61     my($self, $hasvals, $not, @joins)=@_;
62     $not=0 unless(defined($not));
63     my @outjoins=();
64     # init
65     unless(@joins)
66     {
67         @outjoins = @joins = ("INNER");
68     }
69     my $left=$self->left();
70     my $right=$self->right();
71     return ("", @outjoins) unless($left || $right);
72     my ($leftstr, @leftjoins) = $self->node_to_sql($left, $hasvals, $not, @joins);
73     push(@joins, @leftjoins);
74     push(@outjoins, @leftjoins);
75     my $op=$self->op();
76     if(defined($op))
77     {
78         # if we are ANDing, add an inner join
79         # also if we are NOTing, but we are looking for a tag *value*
80         if( ($op->{name}  eq "AND") ||
81             ($hasvals && ($op->{name} eq "NOT")))
82         {
83             # hack - if right child is a NOT, we don't need extra join/brackets
84             # NOT will do the same and we will end up with an extra one
85             unless($right && $right->{op}
86                    && $right->{op}->{name}
87                    && $right->{op}->{name} eq "NOT")
88             {
89                 push(@joins, "INNER");
90                 push(@outjoins, "INNER");
91             }
92         }
93         elsif($op->{name} eq "NOT")
94         {
95             $not=1;
96             push(@joins, "LEFT");
97             push(@outjoins, "LEFT");
98 #           print("LEFT: ", $left->print(), "\n") if ($left);
99 #           print("RIGHT: ", $right->print(), "\n") if($right);
100         }
101     }
102     my ($rightstr, @rightjoins) = $self->node_to_sql($right, $hasvals, $not, @joins);
103     push(@outjoins, @rightjoins);
104 #    print "LEFT (", scalar(@leftjoins), "): $leftstr\n";
105 #    print "RIGHT (", scalar(@rightjoins), "): $rightstr\n";
106     my $str=$leftstr;
107     $str .= (" " . $op->{name} . " ") if($op && !$not);
108     $str .= $rightstr;
109     if($op || ($left && $right))
110     {
111         $str="(" . $str . ")";
112     }
113 #    print "STR: $str\n";
114     return($str, @outjoins);
115 }
116
117 sub node_to_sql
118 {
119     my($self, $node, $hasvals, $not, @joins)=@_;
120     return ("", ()) unless(defined($node));
121     return $node->to_sql($hasvals, $not, @joins) if(ref($node) eq "ID3FS::Path::Node");
122     my $sql;
123     my $cnt=scalar(@joins)+1;
124     if(defined($node->{parents_id}))
125     {
126         $sql= "(t" . scalar(@joins) . ".parents_id='$node->{parents_id}'";
127         $sql .= " AND t" . scalar(@joins) . ".id='" . $node->{id} . "'";
128     }
129     else
130     {
131         $sql= "(t" . scalar(@joins) .".parents_id=''";
132         $sql .= " AND t" . scalar(@joins) . ".id='" . $node->{id} . "'";
133     }
134     if($not && !$hasvals)
135     {
136         $sql .= " AND fxt" . scalar(@joins) . ".files_id IS NULL";
137     }
138     $sql .= ")";
139     return ($sql, ());
140 }
141
142 sub used_tags
143 {
144     my($self)=@_;
145     my @used=(grep { defined; }  ($self->node_used_tags($self->left()),
146                                   $self->node_used_tags($self->right())));
147     return(@used);
148 }
149
150 sub node_used_tags
151 {
152     my($self, $node)=@_;
153     return (undef) unless(defined($node));
154     return $node->used_tags() if(ref($node) eq "ID3FS::Path::Node");
155     if(defined($node->{parents_id}))
156     {
157         return([ $node->{parents_id}, $node->{id} ]);
158     }
159     return $node->{id};
160 }
161
162
163 sub max
164 {
165     my($self, $a, $b)=@_;
166     return(($a > $b) ? $a : $b);
167 }
168
169 1;