// Widget.Chmod by Burak Gürsoy <burak[at]cpan[dot]org>
if (!Widget) var Widget = {};

Widget.Chmod = function ( o ) {
   this.init( o );
}

Widget.Chmod.VERSION   = '0.3';
Widget.Chmod.EXPORT_OK = ['chmod'];
Widget.Chmod.COUNTER   = 0;
Widget.Chmod.DEFAULTS  = {
   // field ids
   'por'     : 'chmod_or',
   'pow'     : 'chmod_ow',
   'pox'     : 'chmod_ox',

   'pgr'     : 'chmod_gr',
   'pgw'     : 'chmod_gw',
   'pgx'     : 'chmod_gx',

   'ppr'     : 'chmod_pr',
   'ppw'     : 'chmod_pw',
   'ppx'     : 'chmod_px',

   'ch1'     : 'chmodval1',
   'ch2'     : 'chmodval2',

   'injectid': 'chmod_inject',

   // style elements
   'size'    : 10,
   'disable' :  1,
   'rtl'     :  0,

   // i18n
   'u'       : 'User',
   'g'       : 'Group',
   'o'       : 'Other',
   'r'       : 'Read',
   'w'       : 'Write',
   'x'       : 'Execute'
};

// protect private object properties
Widget.Chmod.FORBIDDEN  = {
   'IS_DUMB'  : 1,
   'FATAL'    : 1,
   'IS_FATAL' : 1
};

Widget.Chmod.chmod = function ( o ) {
   var id   = 'WidgetChmod' + Widget.Chmod.COUNTER++;
   var CODE = id + " = new Widget.Chmod ( o );"
            + id + '.setid( "' + id + '" );'
            + id + '.inject();'
            + id + '.display();'
            ;
   eval(CODE);
}

Widget.Chmod.prototype.init = function ( o ) {
   var all = document.all;
   var id  = document.getElementById;
   this.IS_DUMB  =  all &&  id      ? 0  //IE5
                 :  all && !id      ? 0  //IE4
                 : !all &&  id      ? 0  //NS6
                 :  document.layers ? 1  //NS4
                 :                    1; //??
   this.FATAL    = "[ Widget.Chmod fatal error ]\n\n";
   this.IS_FATAL = 0;
   if ( o && typeof o == 'object' ) {
      this.value = '';
      for ( key in o ) {
	     if ( Widget.Chmod.FORBIDDEN[key] || (this[key] && typeof this[key] == 'function') ) {
	        return this._fatality(
				      "You have tried to set a private option via constructor."
			         +" Access denied for " + key
			       );
	     }
	     this[key] = o[key];
      }
   }
   if ( this.value ) {
      this.value = this._clean(this.value);
   }
   else {
      return this._fatality("Chmod value is not set");
   }
}

Widget.Chmod.prototype.setid = function ( id ) {
   if ( id ) this.ID = id;
}

Widget.Chmod.prototype.control = function () {
   // controls the value of visual representations (input boxes)
   var o = this._fetch();
   if( !o.ch1.value ) return;

   var t  = 0;
   var sn = this['is_dir'  ] ? 'd'  // directory
          : this['is_block'] ? 'b'  // block special file
          : this['is_char' ] ? 'c'  // character special file
          : this['is_sym'  ] ? 'l'  // symbolic link
          : this['is_pipe' ] ? 'p'  // named pipe
          : this['is_sock' ] ? 's'  // domain socket
          :                    '-'  // regular file
          ;

   if( o.por.checked ) { t += 400; sn += 'r' } else { sn += '-' }
   if( o.pow.checked ) { t += 200; sn += 'w' } else { sn += '-' }
   if( o.pox.checked ) { t += 100; sn += 'x' } else { sn += '-' }

   if( o.pgr.checked ) { t +=  40; sn += 'r' } else { sn += '-' }
   if( o.pgw.checked ) { t +=  20; sn += 'w' } else { sn += '-' }
   if( o.pgx.checked ) { t +=  10; sn += 'x' } else { sn += '-' }

   if( o.ppr.checked ) { t +=   4; sn += 'r' } else { sn += '-' }
   if( o.ppw.checked ) { t +=   2; sn += 'w' } else { sn += '-' }
   if( o.ppx.checked ) { t +=   1; sn += 'x' } else { sn += '-' }

   o.ch1.value = t;  // numeric input
   o.ch2.value = sn; // text input
   if( this._is_disabled() ) o.ch1h.value = t;
}

Widget.Chmod.prototype.display = function ( n ) {
   if ( this.IS_FATAL ) return;
   var o   = this._fetch();
   var val = o.ch1.value;
   if ( !val ) return;
   var e = val.split('');
   switch ( val.length ) {
      case 1:
         this._check( e[0], o.ppr, o.ppw, o.ppx );
         break;
      case 2:
         this._check( e[0], o.pgr, o.pgw, o.pgx );
         this._check( e[1], o.ppr, o.ppw, o.ppx );
         break;
      case 3:
         this._check( e[0], o.por, o.pow, o.pox );
         this._check( e[1], o.pgr, o.pgw, o.pgx );
         this._check( e[2], o.ppr, o.ppw, o.ppx );
         break;
      default:
         return this._fatality(
			       "Initialization failed. Bogus chmod value: "
			       + o.ch1.value
			    );
         break;
   }
   this.control();
}

Widget.Chmod.prototype._fatality = function ( message ) {
   alert( this.FATAL + message );
   this.IS_FATAL = 1;
   if ( this.IS_DUMB ) {
      return;
   }
   else {
      eval( 'throw message' ); // to fool NS4x
   }
}

Widget.Chmod.prototype._param = function ( name ) {
   if( !name ) return;
   var o = document.all            ? document.all[name]
         : document.getElementById ? document.getElementById(name)
         : document.layers         ? this._nsparam(name)
         :                           {};
   return o;
}

Widget.Chmod.prototype._nsparam = function ( name ) {
   var object = document.layers[name];
   if ( !object ) {
      for( var i = 0; i < document.forms.length; i++ ) { // is_form()
         if( !document.forms[i] ) break;
         object = eval( 'document.forms[' + i + '].' + name );
         if( object ) break;
      }
   }
   return object;
}

Widget.Chmod.prototype._pfix = function () {
   var pfix = this['injectid'] || Widget.Chmod.DEFAULTS['injectid'] || '';
   return pfix;
}

Widget.Chmod.prototype._fetch = function () {
   var d    = Widget.Chmod.DEFAULTS;
   var pfix = this._pfix();
   var obj  = {
      'por' : this._param( pfix + ( this['por'] || d['por'] ) ),
      'pow' : this._param( pfix + ( this['pow'] || d['pow'] ) ),
      'pox' : this._param( pfix + ( this['pox'] || d['pox'] ) ),
      'pgr' : this._param( pfix + ( this['pgr'] || d['pgr'] ) ),
      'pgw' : this._param( pfix + ( this['pgw'] || d['pgw'] ) ),
      'pgx' : this._param( pfix + ( this['pgx'] || d['pgx'] ) ),
      'ppr' : this._param( pfix + ( this['ppr'] || d['ppr'] ) ),
      'ppw' : this._param( pfix + ( this['ppw'] || d['ppw'] ) ),
      'ppx' : this._param( pfix + ( this['ppx'] || d['ppx'] ) ),
      'ch2' : this._param( pfix + ( this['ch2'] || d['ch2'] ) ),
      'ch1' : this._param(          this['ch1'] || d['ch1']   ),
      'ch1h': ''
   };
   if ( this._is_disabled() ) {
	  var ch1name = this['ch1'] || d['ch1'];
      obj['ch1h'] = this._param( ch1name + '_disabled' );
   }
   return obj;
}

Widget.Chmod.prototype._clean = function ( n ) {
   if( !n ) return n;
   return n.replace(/^0/, '');
}

Widget.Chmod.prototype._check = function ( bits, r, w, x ) {
   // display() uses a switch() block and make calls to _check()
   // this multiple switch()es seems to confuse firefox' js engine
   // since, using switch() here, breaks the code under Firefox 2x
   // however, IE & Opera works fine. even NS Navigator 4.77 is ok.
   // dumb Firefox :p
        if ( bits == 7 ) { r.checked = 1; w.checked = 1; x.checked = 1; } //rwx
   else if ( bits == 6 ) { r.checked = 1; w.checked = 1;                } //rw-
   else if ( bits == 5 ) { r.checked = 1;                x.checked = 1; } //r-x
   else if ( bits == 4 ) { r.checked = 1;                               } //r--
   else if ( bits == 3 ) {                w.checked = 1; x.checked = 1; } //-wx
   else if ( bits == 2 ) {                w.checked = 1;                } //-w-
   else if ( bits == 1 ) {                               x.checked = 1; } //--x
   else                  {                                              }
}

Widget.Chmod.prototype._is_disabled = function () {
   var d       = Widget.Chmod.DEFAULTS;
   var disable = typeof this['disable'] != 'undefined'
               ?        this['disable']
               :           d['disable'];
   return disable;
}

Widget.Chmod.prototype.inject = function () {
   if ( this.IS_FATAL ) return;
   var pfix      = this._pfix();
   var d         = Widget.Chmod.DEFAULTS;
   var rtl       = this[ 'rtl'] || d['rtl'] || 0;
   var disable   = this._is_disabled();
   var style     = this._get_style();
   var ch1name   = this['ch1' ] || d['ch1' ];
   var ch2name   = this['ch2' ] || d['ch2' ];
   var size      = this['size'] || d['size'];
   var ch1hidden = ch1name;
   if (disable)
   ch1name      += '_disabled';
   var input     = { num : '', str : '' };
   input.num    += ' <input';
   input.num    += ' type  = "text"';
   input.num    += ' name  = "' + ch1name       + '"';
   input.num    += ' id    = "' + ch1name       + '"';
   input.num    += ' value = "' + this['value'] + '"';
   input.num    += ' size  = "' + size          + '"';
   if(disable)
   input.num    += ' disabled="disabled"';
   input.num    += style;
   input.num    += ' /> ';

   input.str    += ' <input';
   input.str    += ' type  = "text"';
   input.str    += ' name  = "' + pfix + (this['ch2'  ] || d['ch2' ]) + '"';
   input.str    += ' id    = "' + pfix + (this['ch2'  ] || d['ch2' ]) + '"';
   input.str    += ' value = ""';
   input.str    += ' size  = "' + size + '"';
   if(disable)
   input.str    += ' disabled="disabled"';
   input.str    += style;
   input.str    += ' /> ';

   if(disable) {
      input.str += '<input';
      input.str += ' type  = "hidden"';
      input.str += ' name  = "' + ch1hidden     + '"';
      input.str += ' id    = "' + ch1hidden     + '"';
      input.str += ' value = "' + this['value'] + '"';
      input.str += ' />';
   }

   var html    = '';
   html += '<table border="0">';
   html += '<tr>';
   html += '<td colspan="3"' + style + '>';
   html += rtl ? input.str + input.num : input.num + input.str;
   html += '</td></tr><tr>';
   html += '<td>' + this._injectf( 'u', 'por', 'pow', 'pox' ) + '</td>';
   html += '<td>' + this._injectf( 'g', 'pgr', 'pgw', 'pgx' ) + '</td>';
   html += '<td>' + this._injectf( 'o', 'ppr', 'ppw', 'ppx' ) + '</td>';
   html += '</tr></table>';
   this.IS_DUMB ? document.write( html ) : this._injection( html );
}

Widget.Chmod.prototype._injection = function ( html ) {
   var d = Widget.Chmod.DEFAULTS;
   var n = this['injectid'] || d['injectid'];
   var o = this._param(n);
   if( !o ) return;
   o.innerHTML = html;
}

Widget.Chmod.prototype._get_style = function () {
   if ( this.IS_DUMB ) return '';
   var d   = Widget.Chmod.DEFAULTS;
   var rtl = this['rtl'] || d[ 'rtl'] || 0;
   return rtl ? ' style="text-align:right"' : '';
}

Widget.Chmod.prototype._injectf = function ( title, r, w, x ) {
   var pfix  = this._pfix();
   var d     = Widget.Chmod.DEFAULTS;
   var rtl   = this[ 'rtl'  ] || d[ 'rtl'  ] || 0;
   var style = this._get_style();
   var td    = '<td'+style+'>';
   var id    = {
      'r' : this[ r ] || d[ r ],
      'w' : this[ w ] || d[ w ],
      'x' : this[ x ] || d[ x ]
   };
   var lang = {
      'r' : this['r'] || d['r'],
      'w' : this['w'] || d['w'],
      'x' : this['x'] || d['x']
   };
   var label = {
      'r' : td + ' <label for="' + pfix + id.r + '" title="' + lang.r + '">' + lang.r + '</label> </td>',
      'w' : td + ' <label for="' + pfix + id.w + '" title="' + lang.w + '">' + lang.w + '</label> </td>',
      'x' : td + ' <label for="' + pfix + id.x + '" title="' + lang.x + '">' + lang.x + '</label> </td>'
   };

   label['rr'] = rtl ? label.r : '';
   label['rw'] = rtl ? label.w : '';
   label['rx'] = rtl ? label.x : '';
   label['lr'] = rtl ? ''      : label.r;
   label['lw'] = rtl ? ''      : label.w;
   label['lx'] = rtl ? ''      : label.x;
   var title   = this[title] || d[title];
   var input   = '<input type="checkbox" name="';
   var onclick = '" onclick="' + this.ID + '.control()" /> ';
   var html    = '<table border="0" cellpadding="0" cellspacing="0">';
       html   += '<tr>' + label.rr + td + input + pfix + id.r + '" id="' + pfix + id.r + onclick + '</td>' + label.lr + "</tr>\n";
       html   += '<tr>' + label.rw + td + input + pfix + id.w + '" id="' + pfix + id.w + onclick + '</td>' + label.lw + "</tr>\n";
       html   += '<tr>' + label.rx + td + input + pfix + id.x + '" id="' + pfix + id.x + onclick + '</td>' + label.lx + "</tr>\n";
       html   += '</table>';
       html    = '<fieldset>' + '<legend>' + title + '</legend>' + html + '</fieldset>';
   if(rtl)
       html    = '<div style="text-align:right">' + html + '</div>';
   return html;
}

/*

*/

