/*
 * Copyright 2003-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.mps.nodeEditor.cells;

import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.smodel.IOperationContext;
import jetbrains.mps.smodel.MPSModuleRepository;
import jetbrains.mps.smodel.NodeReadAccessCasterInEditor;
import jetbrains.mps.smodel.PropertySupport;
import jetbrains.mps.smodel.SModelOperations;
import jetbrains.mps.util.Computable;
import jetbrains.mps.util.annotation.Hack;
import org.jetbrains.mps.openapi.language.SProperty;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeAccessUtil;
import org.jetbrains.mps.openapi.model.SNodeReference;

/**
 * User: shatalin
 * Date: 21/01/15
 */
public class SPropertyAccessor implements ModelAccessor {

  private final SProperty myProperty;
  private final SNode myNode;
  private boolean myReadOnly;
  private boolean myAllowEmptyText;

  public SPropertyAccessor(SNode node, SProperty property, boolean readOnly, boolean allowEmptyText) {
    myNode = node;
    myProperty = property;
    myReadOnly = readOnly;
    myAllowEmptyText = allowEmptyText;
  }

  @Override
  public String getText() {
    return fromInternal(doGetValue());
  }

  @Override
  public void setText(String text) {
    if (!myReadOnly) {
      isValidText(text);
      if (text != null && text.length() == 0) {
        text = null;
      }
      if (isValidText_internal(text)) {
        doSetValue(toInternal(text));
      }
    }
  }

  @Override
  @Hack
  public boolean isValidText(String text) {
    return (isValidText_internal(text) && !isInvalidEmptyText(text));
  }



  public SNode getNode() {
    return myNode;
  }

  public String getPropertyName() {
    return myProperty.getName();
  }



  protected String doGetValue() {
    return NodeReadAccessCasterInEditor.runCleanPropertyAccessAction(new Computable<String>() {
      @Override
      public String compute() {
        if (myNode == null) {
          return null;
        }
        return SNodeAccessUtil.getProperty(myNode, myProperty);
      }
    });
  }

  protected void doSetValue(String newText) {
    SNodeAccessUtil.setProperty(myNode, myProperty, newText);
  }


  private boolean isValidText_internal(String text) {
    if (text != null && text.length() == 0) {
      text = null;
    }

    if (myReadOnly) {
      String propertyValue = getText();
      return (text == null && (propertyValue == null || propertyValue.isEmpty())) || (text != null && text.equals(propertyValue));
    }

    PropertySupport propertySupport = PropertySupport.getPropertySupport(myProperty);
    return propertySupport.canSetValue(myNode, myProperty, text);
  }

  @Hack
  private boolean isInvalidEmptyText(String text) {
    return !myAllowEmptyText && (text == null || text.length() == 0);
  }

  private String fromInternal(String value) {
    PropertySupport propertySupport = PropertySupport.getPropertySupport(myProperty);
    return propertySupport.fromInternalValue(value);
  }

  private String toInternal(String value) {
    PropertySupport propertySupport = PropertySupport.getPropertySupport(myProperty);
    return propertySupport.toInternalValue(value);
  }

}
